B4J NES Emulator Project
B4JNES - Complete Documentation and Sourcecode
Overview
The B4J NES Emulator is a comprehensive Nintendo Entertainment System (NES) emulator written in B4J (Basic for Java). It provides accurate emulation of the NES hardware including the CPU, PPU, APU, and various memory mappers.
Features
- Complete 6502 CPU Emulation: All 151 official opcodes plus 105 undocumented opcodes
- Accurate PPU Emulation: Cycle-accurate rendering with proper sprite evaluation
- APU Sound Support: All 5 audio channels (2 pulse, triangle, noise, DMC)
- 25+ Memory Mappers: Support for most common NES games
- Game Genie Support: Built-in cheat code system
- Save States: Save and load game progress
- Debug Tools: Sprite viewer, audio visualizer, ROM analyzer
System Requirements
- Java Runtime Environment 8 or higher
- B4J IDE (for development)
- Minimum 512MB RAM recommended
License
This software is released under the GNU General Public License v3.0 (GPL-3.0).
Copyright (C) 2026 B4J NES Emulator Project
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <
https://www.gnu.org/licenses/>.
GPL-3.0 Compliance Notes
All source files include the standard GPL-3.0 header. When distributing modified versions:
- Include the complete source code
- Maintain all copyright notices
- Document any modifications
- Use the same GPL-3.0 license
Architecture
Component Diagram
Data Flow
- ROM Loading: CARTRIDGE parses iNES/NES 2.0 headers and loads PRG/CHR data
- Mapper Selection: MAPPERBASE selects and initializes appropriate mapper
- Frame Execution: NESEMULATOR runs CPU instructions and syncs PPU
- Rendering: PPU generates pixel data, output to display buffer
- Audio: APU generates samples, sent to audio output
Core Components
NESEMULATOR.bas
Purpose: Main emulation controller that coordinates all components.
Key Functions:
| Function | Description |
|---|
| Initialize() | Initializes all emulator components |
| LoadROM(fileName) | Loads a NES ROM file |
| ExecFrame() | Executes one complete video frame |
| ResetSoft() | Soft reset (preserves RAM) |
| ResetHard() | Hard reset (clears all state) |
| SaveStateToFile() | Saves emulation state |
| LoadStateFromFile() | Restores emulation state |
Timing Constants:
- CPU_CYCLES_PER_FRAME: 29,780 (NTSC)
- PAL_CPU_CYCLES_PER_FRAME: 33,248 (PAL)
- PPU_CYCLES_PER_CPU: 3
CPU6502.bas
Purpose: Emulates the MOS 6502 processor used in the NES (specifically the Ricoh 2A03).
Registers:
| Register | Size | Description |
|---|
| A | 8-bit | Accumulator |
| X | 8-bit | X Index Register |
| Y | 8-bit | Y Index Register |
| SP | 8-bit | Stack Pointer ($01xx) |
| PC | 16-bit | Program Counter |
| P | 8-bit | Processor Status |
Status Flags (P Register):
| Bit | Flag | Description |
|---|
| 7 | N | Negative |
| 6 | V | Overflow |
| 5 | - | Unused (always 1) |
| 4 | B | Break |
| 3 | D | Decimal Mode |
| 2 | I | Interrupt Disable |
| 1 | Z | Zero |
| 0 | C | Carry |
Addressing Modes:
- Implied: No operand (e.g., NOP, RTS)
- Accumulator: Operates on A (e.g., ASL A)
- Immediate: #$nn (e.g., LDA #$10)
- Zero Page: $nn (e.g., LDA $10)
- Zero Page,X: $nn,X (e.g., LDA $10,X)
- Zero Page,Y: $nn,Y (e.g., LDX $10,Y)
- Absolute: $nnnn (e.g., LDA $1234)
- Absolute,X: $nnnn,X (e.g., LDA $1234,X)
- Absolute,Y: $nnnn,Y (e.g., LDA $1234,Y)
- Indirect: ($nnnn) (JMP only)
- Indexed Indirect: ($nn,X) (e.g., LDA ($10,X))
- Indirect Indexed: ($nn),Y (e.g., LDA ($10),Y)
Interrupt Vectors:
| Address | Type |
|---|
| FFFA−FFFA−FFFB | NMI |
| FFFC−FFFC−FFFD | RESET |
| FFFE−FFFE−FFFF | IRQ/BRK |
PPU.bas
Purpose: Emulates the Picture Processing Unit (2C02).
Resolution: 256x240 pixels, 64 colors
Key Registers:
| Address | Name | Description |
|---|
| $2000 | PPUCTRL | Control register |
| $2001 | PPUMASK | Mask register |
| $2002 | PPUSTATUS | Status register |
| $2003 | OAMADDR | OAM address |
| $2004 | OAMDATA | OAM data |
| $2005 | PPUSCROLL | Scroll position |
| $2006 | PPUADDR | VRAM address |
| $2007 | PPUDATA | VRAM data |
Timing:
- 341 PPU cycles per scanline
- 262 scanlines per frame (NTSC)
- 312 scanlines per frame (PAL)
Memory Layout:
| Range | Size | Description |
|---|
| $0000-$0FFF | 4KB | Pattern Table 0 |
| $1000-$1FFF | 4KB | Pattern Table 1 |
| $2000-$23FF | 1KB | Nametable 0 |
| $2400-$27FF | 1KB | Nametable 1 |
| $2800-$2BFF | 1KB | Nametable 2 |
| $2C00-$2FFF | 1KB | Nametable 3 |
| $3F00-$3F1F | 32B | Palettes |
APU.bas
Purpose: Emulates the Audio Processing Unit.
Channels:
| Channel | Type | Description |
|---|
| Pulse 1 | Square Wave | Duty cycle, sweep, envelope |
| Pulse 2 | Square Wave | Duty cycle, sweep, envelope |
| Triangle | Triangle Wave | Linear counter |
| Noise | LFSR Noise | Mode select, envelope |
| DMC | Delta PCM | Sample playback |
Registers ($4000-$4017):
| Range | Channel |
|---|
| $4000-$4003 | Pulse 1 |
| $4004-$4007 | Pulse 2 |
| $4008-$400B | Triangle |
| $400C-$400F | Noise |
| $4010-$4013 | DMC |
| $4015 | Status/Control |
| $4017 | Frame Counter |
MEMORY.bas
Purpose: Memory bus controller handling all CPU memory access.
Memory Map:
| Range | Size | Description |
|---|
| $0000-$07FF | 2KB | Internal RAM |
| $0800-$1FFF | - | RAM Mirrors |
| $2000-$2007 | 8B | PPU Registers |
| $2008-$3FFF | - | PPU Register Mirrors |
| $4000-$4017 | - | APU/IO Registers |
| $4018-$401F | - | Disabled APU/IO |
| $4020-$5FFF | - | Expansion ROM |
| $6000-$7FFF | 8KB | Battery-backed RAM |
| 8000−8000−BFFF | 16KB | PRG ROM Bank 0 |
| C000−C000−FFFF | 16KB | PRG ROM Bank 1 |
CARTRIDGE.bas
Purpose: ROM loading and parsing.
Supported Formats:
- iNES 1.0 (.nes)
- NES 2.0 (.nes)
Header Structure (16 bytes):
| Offset | Size | Description |
|---|
| 0-3 | 4B | “NES” + $1A |
| 4 | 1B | PRG ROM size (16KB units) |
| 5 | 1B | CHR ROM size (8KB units) |
| 6 | 1B | Flags 6 |
| 7 | 1B | Flags 7 |
| 8-15 | 8B | Extended flags |
Mirroring Modes:
- 0: Horizontal
- 1: Vertical
- 2: Four-screen
- 3: Single-screen (lower)
- 4: Single-screen (upper)
Memory Mapping
Bank Switching
The emulator uses 1KB bank granularity for both PRG and CHR:
PRG Banks: 32 x 1KB banks covering 8000−8000−FFFF
CHR Banks: 8 x 1KB banks covering $0000-$1FFF
Bank Swap Functions
' PRG bank swap
mem.PRGswap(banknum, newbank, banksize)
' CHR bank swap
mem.CHRswap(banknum, newbank, banksize)
Supported Mappers
| Mapper | Name | Description |
|---|
| 0 | NROM | No bank switching |
| 1 | MMC1 | Nintendo’s first mapper |
| 2 | UxROM | Simple PRG switching |
| 3 | CNROM | Simple CHR switching |
| 4 | MMC3 | Most popular mapper |
| 5 | MMC5 | Advanced mapper |
| 7 | AxROM | Single-screen mirroring |
| 9 | MMC2 | Punch-Out!! mapper |
| 10 | MMC4 | Fire Emblem mapper |
| 11 | Color Dreams | Unlicensed |
| 22 | VRC2a | Konami |
| 23 | VRC2b/VRC4 | Konami |
| 24 | VRC6 | Konami with audio |
| 25 | VRC4b/VRC4d | Konami |
| 28 | Action 53 | Modern homebrew |
| 34 | BNROM/NINA | Simple PRG |
| 62 | Multicart | Multi-game |
| 66 | GxROM | Simple |
| 69 | Sunsoft FME-7 | With audio |
| 71 | Camerica | Codemasters |
| 83 | Yoko/Cony | Pirate |
| 118 | TxSROM | MMC3 variant |
| 221 | NTDEC | Multicart |
| 227 | Multicart | Multi-game |
API Reference
NESEMULATOR Class
Initialize()
Initializes all emulator components. Must be called before loading a ROM.
LoadROM(fileName As String) As Boolean
Loads a NES ROM file.
- Parameters: fileName - Full path to .nes file
- Returns: True if successful
ExecFrame()
Executes one complete video frame (~29,780 CPU cycles).
ResetSoft()
Performs a soft reset, preserving RAM contents.
ResetHard()
Performs a hard reset, clearing all memory.
Start() / Stop()
Controls emulation execution state.
KeyPressed(keyName As String) / KeyReleased(keyName As String)
Handles controller input.
CPU6502 Class
Initialize(m As Object)
Initializes CPU with memory interface.
Reset()
Resets CPU to power-on state.
Step() As Int
Executes one instruction, returns cycles consumed.
DoNMI()
Triggers Non-Maskable Interrupt.
DoIRQ()
Triggers Interrupt Request (if enabled).
PPU Class
Initialize(memRef, mapperRef, cartRef, cpuRef)
Initializes PPU with component references.
Tick() As Boolean
Executes one PPU cycle. Returns True when frame complete.
ReadRegister(addr As Int) As Int
Reads PPU register ($2000-$2007).
WriteRegister(addr As Int, value As Int)
Writes PPU register.
Building and Running
Prerequisites
- Install B4J IDE from https://www.b4x.com/b4j.html
- Install Java JDK 8 or higher
Build Steps
- Open NES.b4j in B4J IDE
- Configure libraries path in IDE settings
- Click Build/Run or press F5
Default Controls
Controller 1:
| Button | Key |
|---|
| A | F |
| B | D |
| Select | S |
| Start | Enter |
| D-Pad | Arrow Keys |
Controller 2:
| Button | Key |
|---|
| A | J |
| B | H |
| Select | N |
| Start | M |
| D-Pad | I/K/U/O |
System Keys:
| Function | Key |
|---|
| Pause/Unpause | Escape |
| HUD | F1 |
| Record Audio Start | F2 |
| Recording Stop | F3 |
| Screenshot to Clipboard | F12 |
File List
| File | Description |
|---|
| APU.bas | Audio Processing Unit - generates NES audio |
| AudioViewer.bas | Debug audio visualizer |
| CARTRIDGE.bas | ROM loader and cartridge management |
| CPU6502.bas | 6502 CPU emulation core |
| CRC32.bas | CRC32 checksum calculator |
| GAMEGENIE.bas | Game Genie cheat code engine |
| GameGenieDialog.bas | Game Genie code entry dialog |
| INPUTHANDLER.bas | Controller input handler |
| InputConfigDialog.bas | Controller configuration GUI |
| MAPPER000.bas | Mapper 0 - NROM (no mapper) |
| MAPPER001.bas | Mapper 1 - MMC1 (SxROM) |
| MAPPER002.bas | Mapper 2 - UxROM |
| MAPPER003.bas | Mapper 3 - CNROM |
| MAPPER004.bas | Mapper 4 - MMC3 (TxROM) |
| MAPPER005.bas | Mapper 5 - MMC5 (ExROM) |
| MAPPER007.bas | Mapper 7 - AxROM |
| MAPPER009.bas | Mapper 9 - MMC2 (PxROM) |
| MAPPER010.bas | Mapper 10 - MMC4 (FxROM) |
| MAPPER011.bas | Mapper 11 - Color Dreams |
| MAPPER022.bas | Mapper 22 - VRC2a |
| MAPPER023.bas | Mapper 23 - VRC2b/VRC4 |
| MAPPER024.bas | Mapper 24 - VRC6a |
| MAPPER025.bas | Mapper 25 - VRC4b/VRC4d |
| MAPPER028.bas | Mapper 28 - Action 53 |
| MAPPER034.bas | Mapper 34 - BNROM/NINA-001 |
| MAPPER062.bas | Mapper 62 - Super 700-in-1 |
| MAPPER066.bas | Mapper 66 - GxROM |
| MAPPER069.bas | Mapper 69 - FME-7/Sunsoft 5B |
| MAPPER071.bas | Mapper 71 - Camerica/Codemasters |
| MAPPER083.bas | Mapper 83 - Cony/Yoko |
| MAPPER118.bas | Mapper 118 - TxSROM (MMC3 variant) |
| MAPPER221.bas | Mapper 221 - N625092 |
| MAPPER227.bas | Mapper 227 - 1200-in-1 |
| MAPPERBASE.bas | Base mapper class and mapper factory |
| MEMORY.bas | Memory bus controller |
| NESEMULATOR.bas | Main emulator controller |
| PPU.bas | Picture Processing Unit - graphics rendering |
| ROMAnalyzer.bas | ROM information analyzer |
| SAVESTATE.bas | Save state management |
| SpriteViewer.bas | Debug sprite viewer
|
Changelog
Version 1.1.0
- Added pause/unpause functionality (ESC key)
- Added screenshot to clipboard (F12 key)
- Added controller configuration dialog (InputConfigDialog)
- Configurable key bindings with save/load support
- Code refactoring with getter/setter encapsulation
- Input validation and bounds checking throughout
Version 1.0.0
- Initial release with GPL-3.0 license
- Support for 25+ mappers
- Full CPU, PPU, and APU emulation
- Game Genie support
- Save state support
- Debug tools
Documentation for B4J NES Emulator Project
Licensed under GPL-3.0