Machine::save_state and load_state encode the CPU, every RAM, and every device through Snapshot impls into a versioned, checksummed format. Rejected loads leave the machine unchanged. The ROM window saves to and loads from one state file with F5 and F9.
26 KiB
Project status
What the emulator does today, what it deliberately leaves out, and what comes next. Update this file when a feature lands or a limit is removed.
Current behavior
- Native desktop window, with animation and keyboard controls for display testing.
- Platform-independent 240×160 framebuffer and GBA RGB555 color conversion.
- Optional row capture at HBlank, double-buffered frame publication at VBlank, and retained mid-frame changes.
- CPU-configured HBlank DMA raster demo with per-row palette changes.
- Mode 0 tile backgrounds: 4-bit/8-bit pixels, palettes, flips, scrolling, map sizes, transparency, and priorities.
- Mode 3 video RAM snapshots, BG2 enable, palette backdrop, forced blank, and green swap.
- Mode 1 mixed text/affine backgrounds and Mode 2 affine backgrounds, with signed transforms and map wrapping/clipping.
- Mode 3/4/5 bitmap transforms through BG2 affine registers, with Mode 4/5 page selection.
- Mode 4 indexed colors and transparent index zero; Mode 5 opaque 160×128 RGB555 pixels.
- Regular and affine sprites in Modes 0–5: palettes, rotation, scaling, flips, clipping, and priority selection.
- One-line-ahead sprite row preparation, with buffered palette indices and metadata.
- Background and sprite mosaic, with independent 1–16 pixel dimensions and per-layer enable flags.
- Separate live vertical mosaic counters for backgrounds and sprites, with phase-preserving size writes.
- WIN0/WIN1 rectangles and OBJ window masks, with per-region layer and color-effect controls.
- Vertical WIN0/WIN1 edge tracking across visible rows, VBlank, and frame boundaries.
- Horizontal WIN0/WIN1 comparator history, including mid-line writes and offscreen edges.
- Alpha blending, brightness increase/decrease, and semi-transparent sprites using five-bit color arithmetic.
- 96 KiB video RAM, 1 KiB palette RAM, and 1 KiB object attribute memory, with mirrors and byte-write behavior.
- Active-low
KEYINPUTfor all ten GBA buttons, independent of the window library. KEYCNTselection and OR/AND matching, keypad IRQ latching, and HALT wake-up through IE bit 12.- Original ARM graphics demo that uses DMA, BIOS VBlank waiting, and a ROM-side IRQ callback.
- Sixteen active 32-bit CPU registers, with ARM7 mode-specific register banks.
- Persistent ARM/Thumb instruction buffering, sequential fetch retention, branch/vector target pairs, and deferred fetch diagnostics.
- Shared mapped fetch samples for instruction retention, supported open-bus values, BIOS snapshots, and IWRAM refill history.
- User, System, Supervisor, IRQ, FIQ, Abort, and Undefined modes.
- Current and saved program status registers (
CPSR/SPSR), withMRS/MSRtransfers. - ARM/Thumb software interrupts (
SWI), exception vectors, and status-restoring returns. - CPU interrupt entry, interrupt masks, and FIQ priority.
- GBA interrupt enable (
IE), request flags (IF), and master enable (IME) registers. - Four 16-bit timers, with reloads, prescalers, count-up cascading, and timer-generated IRQs.
- A shared free-running timer divider survives enable and clock-source changes; HALT advances it and STOP freezes it.
- A 228-line display clock, VCOUNT/DISPSTAT, and VBlank/HBlank/VCount-match interrupts.
- Four direct memory access (DMA) channels, with immediate, VBlank, and visible-line HBlank triggers.
- Halfword/word DMA, address controls, repeat, channel priority, CPU pausing, and completion IRQs.
- Separate retained DMA channel data, with known-value reuse for blocked sources below work RAM.
- One-shot non-sequential nominal CPU code timing after successful DMA, including RAM-only transfers.
- HALT with enabled-request wake-up, continued device clocks, and bounded idle steps.
- BIOS-only CPU writes to POSTFLG/HALTCNT, with HALT and keypad-wake STOP.
- STOP freezes CPU/DMA/GBA-device clocks, retains device phases, and reports a stopped frame runner without spinning.
- Machine execution to the next VBlank event, with a configurable step limit.
- CPU/device stepping with nominal ARM7 instruction costs and memory wait states.
- Ordered CPU timing transactions record source, data, internal, and refill costs, with whole-step diagnostic rollback.
- Code costs use actual ARM PC+8/Thumb PC+4 source fetches and branch/exception target pairs, including region and ROM boundaries.
- IRQ entry samples its discarded incoming-state fetch before the ARM vector pair, with local IWRAM history updates.
- Persistent fetch access kinds follow CPU data/internal work, compose with DMA resume, and reset after target refills.
- Game Pak wait-state control (
WAITCNT) for all three ROM windows and supported save-byte accesses. - Bit 14 enables a nominal eight-halfword opcode prefetch queue, with partial fetches, cancellation, and DMA/idle integration.
- Staged timer/audio/serial clocks follow CPU and DMA bus-completion phases, including timer/serial IF reads, acknowledgements, and failed-step rollback.
- The unchanged original ARM cancellation probe matches both published read interval totals and its unadjusted timer samples.
- Sequential/non-sequential data accesses, branch refill costs, and variable multiply timing.
- Optional caller-supplied 16 KiB BIOS mapping, with CPU read protection based on retained ARM PC+8 or aligned Thumb PC+4 words.
- CPU/DMA writes to the mapped BIOS complete without changing its image; host writes retain read-only diagnostics.
- Optional original BIOS replacement: minimal boot, SoftReset, selective RegisterRamReset, IRQ dispatch, interrupt waits, memory copy/fill, integer/fixed-point arithmetic, affine matrices, bit unpacking, LZ77/run-length/Huffman decompression, and differential filters.
- All 16 ARM data-processing operations, with immediate and shifted-register operands.
- Logical operations:
AND,EOR,TST,TEQ,ORR,MOV,BIC, andMVN. - Arithmetic operations:
SUB,RSB,ADD,ADC,SBC,RSC,CMP, andCMN. - Logical and arithmetic shifts, rotate-right, and rotate-right through carry (
RRX). - Immediate and register-specified shift amounts, including zero and amounts of 32 or more.
MUL,MLA,UMULL,UMLAL,SMULL, andSMLAL.- Negative (N), zero (Z), carry (C), and signed overflow (V) flags.
- All 15 defined ARM condition codes, including always (
AL). BandBLwith signed relative displacement and conditional execution.BXswitches between ARM and Thumb using target bit zero.LDR,STR,LDRB,STRB,LDRH,STRH,LDRSB, andLDRSH.- Single-load base/destination aliases retain the loaded value over writeback for r0–r14, across word, byte, halfword, and signed loads.
- Pre/post-indexed addressing, positive/negative offsets, and base-register writeback.
LDM/STMin increment-after, increment-before, decrement-after, and decrement-before modes.- Stack save/restore, PC loads, empty register lists, and ARM7 base-register overlap rules.
SWP/SWPB, including unaligned word rotation and register aliases.- 256 KiB external work RAM and 32 KiB internal work RAM, including mirrors.
- Read-only cartridge bytes in the three GBA cartridge windows.
- Explicit cartridge RTC selection with first-window GPIO read enable, direction/latch behavior, and serial calendar/control transactions.
- Validated RTC date/time, BCD transfers, read snapshots, complete writes/reset, and caller-supplied battery-clock advancement.
- Desktop
--rtcseeds UTC once and supplies host elapsed seconds independently of CPU cycles and STOP. - Cartridge GPIO and Flash controller changes participate in CPU/DMA rollback and block-store preflight without modifying ROM bytes.
- Explicit Macronix Flash64/Flash128 identification, bank selection, delayed byte programming, sector/chip erase, and nominal DQ7 polling.
- Transactional Flash completion and modification tracking, with exact-size core image loading and inspection.
- Optional desktop
--save-fileloading and clean-exit persistence, with exclusive locks, atomic installation, and unique previous-image backups. - Original ROM save/restart/load checks across processes, including native-window persistence on Darwin arm64.
- Whole-machine save states:
Machine::save_state/load_statewith image and cartridge identity checks, a checksum, and verify-before-mutate loading; ROM windows bind F5 (save) and F9 (load) to a--state-fileslot. - Raw ROM-file loading with original BIOS boot, terminal diagnostics, and final CPU/step reports.
- Firmware boot initializes BG2/BG3 identity scales for bitmap and affine programs that do not program their own matrices.
- RegisterRamReset supports disabled sound and disconnected serial initialization, including the common
r0=0xffrequest. - Both LZ77 BIOS services return without output for zero-length headers, including all-zero headers; nonempty validation remains strict.
- Disconnected Joybus selection, local data/status registers, and transmit-pending state without invented remote events or IRQs.
- Direct Sound A/B support timer-driven FIFO playback, stereo digital levels, and DMA1/A or DMA2/B refill blocks.
- PSG pulse channels 1 and 2 support independent nominal frequency/duty playback, length, envelope, status, and stereo mixing. Channel 1 also supports sweep.
- Noise channel 4 supports nominal 7/15-bit generation, divider clocks, shared length/envelope behavior, status, and stereo mixing.
- Wave channel 3 supports single-bank nibble playback, rotating RAM, volume/force-volume, length, activity status, and digital mixing.
- Two-bank wave playback, active bank changes, and unsupported serial operations remain diagnostic with whole-access and block-store rollback.
- ROM windows with scanline capture, keyboard input, focus-loss release, bounded execution slices, and interactive keypad wake from STOP.
- Opt-in macOS CoreAudio output, with tested original tones and wave-ROM playback; focus loss and STOP mute queued audio.
- ROM-window
--speed 1..16targets accelerated playback through host pacing only; audio is muted above 1×. - Optional ROM-window frame limits and an original input-test ROM generator.
- Headless JSON ROM suites with PC or VBlank completion, register/CPSR/memory/pixel assertions, scheduled buttons, bounded budgets, and structured failure reports.
- Hash-pinned preparation of public
jsmolka/gba-testsARM, Thumb, memory, and BIOS ROMs, with verified result-register checkpoints. - These pinned ROMs pass their checkpoints on Darwin arm64 in debug and release builds; coverage limits remain documented.
- A pinned MIT Pong homebrew passes captured-pixel menu, ball-motion, and paddle press/release checks in both profiles. A bounded native-window run also completes; scoring, full playthrough, audio, and saves are not validated by this ROM.
- The original BIOS exposes documented boot, SoftReset, SWI, and IRQ protected-read words through its actual exit layout.
- ARM test/compare Rd=15 status restoration, without a PC result write or nominal refill.
- ARM unused-memory data reads return a PC+8 word snapshot, with normal byte lanes and load rotation.
- Thumb unused-memory reads follow the actual PC+4 fetch region, including mapped boundaries, ROM windows, and IWRAM lane history.
- Persistent IWRAM lanes track ARM/Thumb fetches, CPU data accesses, and successful DMA, with known-bit tracking and diagnostic rollback.
- Cold fills, ARM/Thumb target pairs, and discarded IRQ source fetches update addressed IWRAM lanes; state changes do not erase them.
- Little-endian byte, halfword, and word reads/writes.
- ARM7TDMI word-load rotation, aligned stores, and odd-address halfword-load behavior.
- Explicit errors for unsupported instructions when their condition passes, and for unsupported memory accesses.
Thumb execution includes:
- Immediate and register arithmetic, shifts, comparisons, logical operations, and multiply.
- High-register operations and
BX. - Word, byte, halfword, and signed loads/stores with register or immediate offsets.
- PC-relative literal loads, PC/SP-relative address calculation, and stack-pointer adjustment.
PUSH/POPand multiple-register loads/stores, including PC+6 stores for empty register lists.- All 14 conditional branches, unconditional branches, and both halves of
BL.
Deliberate limits
This is an interpreter scaffold, not an accurate GBA implementation.
It models CPU reset state and an optional minimal firmware subset, not the complete GBA boot sequence or BIOS service set.
Status handling covers ARM7 flags, modes, interrupt masks, and instruction state; reserved bits read as zero.
The reserved ARM condition code 0xF and Thumb condition code 0xE return errors.
ARMv5+ extensions such as BLX, BKPT, and Thumb-2 instructions are not supported.
The ARMv4T high-register format requires at least one high register; low-to-low forms in that format return errors.
LDRT/STRT single-transfer variants and invalid register combinations return errors.
CPU BIOS reads are protected by the executing address using bounded ARM and Thumb prefetch snapshots.
Thumb BIOS execution retains the full word at (PC+4) & ~3, not a repeated halfword.
Missing lookahead invalidates that history; protected reads with unknown history remain diagnostics.
Exact refill and BIOS data-access ordering remain unmodeled. The Thumb rule has source-based, not physical-hardware validation.
This is not a full fetch pipeline. The original BIOS reproduces documented boundary readback words, not all firmware side effects.
Multiply flags N/Z are implemented. Unspecified multiply C/V outputs are preserved deterministically, not hardware-verified.
Instruction and memory errors are development diagnostics, not emulated CPU exceptions.
Block transfers validate all accesses before committing register, RAM, or I/O changes.
This diagnostic policy does not reproduce partial transfers during hardware data aborts.
CPU instructions, including swaps, finish before a newly requested DMA unit runs. Sub-instruction bus arbitration is not modeled.
CPU/bus costs are nominal estimates, not a cycle-accurate implementation.
The instruction buffer retains the next fetch kind; cold startup costs and per-access device scheduling remain unmodeled.
Game Pak prefetch uses source-backed queue rules, not hardware-verified timing.
Live WAITCNT transitions, page-boundary behavior, and exact DMA/idle ordering still need independent timing validation.
Timer data accesses follow ordered nominal bus phases. Other devices remain instruction-batched; exact timer startup and IRQ delays remain unverified.
Graphics support includes Mode 0–5 debug snapshots and HBlank row capture with sprites, mosaic, windows, and color effects.
Internal affine origins, vertical window flags, and vertical mosaic counters track line boundaries.
Horizontal window comparators retain four-cycle event history.
Sprite rows prepare one line ahead with a whole-row cycle40 sample and nominal per-row work limits.
Individual fetch timing, hardware-accurate work cutoffs, video-bus contention, and per-pixel color composition remain unimplemented.
ROM windows offer opt-in Darwin audio output with --audio and explicit save persistence with --save-file.
The Flash subset supports programming and erase with nominal delays and bounded DQ7 polling.
Flash timing, STOP clocking, and cancellation are not hardware-verified. Wider accesses and unverified busy addresses remain diagnostic.
SRAM, EEPROM, other manufacturers, autosave, crash recovery, and game-level save transactions remain unsupported.
Persistence is tested on Darwin arm64 with original programs, not yet with external-game saves.
The optional cartridge GPIO/RTC subset supports calendar/control transfers and explicit clock updates, selected with --rtc in ROM modes.
RTC persistence, interrupts, invalid-date correction, physical subsecond timing, GPIO aliases, and byte writes remain unsupported or unverified.
The core uses deterministic caller time. Desktop RTC runs use host UTC/elapsed time and are not fully deterministic.
The audio subset supports Direct Sound, both PSG pulse channels, single-bank wave channel 3, noise channel 4, and instantaneous digital mixing.
Optional 32,768 Hz digital capture provides bounded, transactional stereo samples with explicit drop counts.
Two-bank wave playback, active wave-bank changes, and unverified sound-DMA pairings remain diagnostic.
PSG timing and signed mixing are nominal; hardware startup edges and analog behavior remain unverified.
The serial subset supports disconnected normal 8/32-bit transfers, external-clock waiting, idle multiplayer configuration, and general-purpose pins.
Internal clocks shift high input at nominal rates, clear busy, and request completion IRQs. External requests retain busy without clock edges.
Disconnected multiplayer exposes child/ready status and 16-bit send/receive registers without inventing transfers or completion IRQs.
Pre-transfer ID is a zero placeholder; receive-write behavior and reset/alias details lack physical-hardware validation.
Joybus supports local configuration, data latches, and transmit-pending status, without an external master or completion IRQs.
Connected links, multiplayer transfers, UART, Joybus commands, GPIO interrupts, and unverified mid-transfer reconfiguration remain unsupported.
RCNT retains inactive bits 8/14 in normal mode and bit 8 in Joybus. Effective GPIO interrupt enable remains diagnostic.
Mapped I/O covers DMA, timers, interrupts, WAITCNT, display control/status, background control/scroll/affine registers, window/effect registers, KEYINPUT/KEYCNT, POSTFLG, and HALTCNT.
Keypad IRQs use a documented polling model; hardware retrigger edges and asynchronous input timing remain unverified.
STOP implements keypad wake only. Serial/Game Pak wake sources, oscillator restart delays, and exact wake timing remain unimplemented or unverified.
The presentation framebuffer is separate from emulated video RAM.
All named graphics demos connect desktop input and rendering to the emulated CPU. The default display test remains host-generated.
ROM files can run in bounded terminal mode or a window with the original BIOS replacement.
ROM windows have no demo-specific startup checks. Input is sampled between bounded execution slices.
Audio is muted by default; --audio opens the macOS output device for ROM windows only. Save files require explicit selection; external BIOS loading remains unavailable.
The host output has bounded buffers, linear rate conversion, DC removal, and underrun/drop counters. Slow hosts can stutter.
ROM loading and nonzero audio callbacks do not establish commercial-game compatibility or correct music.
A local Emerald run now completes its all-device reset and master sound enable.
It also passes the pulse/noise triggers and normal-mode RCNT configuration.
It also completes a CpuSet call to address zero through the corrected ignored BIOS-write behavior.
It also accepts an external-clock serial request without inventing clock edges or completion.
It now also completes internally clocked normal transfers and selects idle multiplayer mode.
With explicit --rtc selection, it also passes Game Pak GPIO configuration and RTC calendar reads.
With --save-type flash128, it also passes Flash identification and reaches a later startup check.
It now passes disconnected Joybus setup and completes a bounded 600-frame native run without a diagnostic error.
That run used no scripted input or pixel assertions.
A fixed-time input probe found a wave trigger with its gate disabled.
Wave support now passes that point and reaches 1,320 frames with scheduled Start/A presses and releases.
Output differs from a no-input control, but readable menus and gameplay remain unverified.
Flash writing and host persistence now pass original save/restart/load tests. Emerald saving and reloading remain unverified; save states offer a separate restore point.
A user reached starter selection, then reported a BIOS invalid-argument trap.
An isolated reproduction identified a zero-length LZ77 header rejected before the length check.
The replacement BIOS now returns for that empty stream. Full starter-selection progress after this correction needs user retesting.
A later visible-progress probe renders the title screen, logo, NEW GAME/OPTION menu, Prof. Birch scene, and legible dialogue in attract mode.
Sparse A/Start taps reach the gender prompt by 4,000 frames and the in-game start menu over the overworld by 12,000 frames without a diagnostic.
A 40,000-frame tapped run passed the reported 37,101-frame trap point without a diagnostic; blind taps take a different menu path, so the identical scene is not confirmed visited.
Text/affine background map and tile fetches now follow the 128 KiB VRAM mirror window instead of faulting past 64 KiB; this fixes a user-reported window diagnostic at map address 0x10d00 after 23,024 captured frames.
See the startup result for the bounded run and next investigation.
See cartridge loading for file limits, step budgets, and exit status.
The ROM suite runner has original regressions and a pinned public ARM baseline.
The pinned public ARM ROM passes its result checkpoint in debug and release builds.
The pinned public Thumb ROM also passes after correcting its empty-list store PC value.
The pinned public memory ROM passes without a core change; its video-byte assertions have documented limits.
The pinned BIOS read-protection ROM passes after correcting the replacement firmware's exit layout.
The bus still derives retained words from the actual image; no test-specific override or ROM patch is used.
Other public suites remain unverified. These results do not establish full CPU or memory compatibility.
The runner supports PC checkpoints or bounded VBlank completion, scripted button snapshots, and captured-pixel assertions.
Debug-port logging, audio assertions, and whole-image comparisons remain unsupported.
ARM data reads from unused address ranges use a bounded PC+8 open-bus snapshot. Thumb reads use region-dependent snapshots and persistent local IWRAM lanes. Only actual IWRAM fetches and data accesses drive those lanes, independently of CPU state and executing region. Cold fills and target pairs establish both lanes when all required samples are mapped. State changes and other-region accesses preserve local history; an IRQ source fetch updates lanes when it addresses IWRAM. Failed instructions discard staged updates. Successful DMA can establish lanes before CPU startup. Resumed fetches then update their addressed lanes. ARM/Thumb instruction buffering retains sequential instructions and refill target pairs. Instruction buffering and supported bus history now consume the same mapped fetch samples, without sharing retained storage. Mapped boundary snapshots follow the actual fetched bus; unknown IWRAM lanes, missing bytes, and I/O fetch values remain diagnostic. Complete general-bus history, exact boundary timing, general DMA handoff, and unused/write-only I/O open bus remain incomplete. DMA channel data latches support blocked-source reuse, but never replace CPU bus history. BIOS protection uses separate retained BIOS fetch snapshots as described in BIOS behavior. Host inspection and instruction fetches remain strict. Other unmapped reads return errors. Reads beyond the supplied cartridge bytes also return errors. Direct memory-bus halfword and word accesses require alignment. CPU load/store instructions apply ARM7TDMI alignment and rotation rules before accessing the bus. Ordinary ROM writes remain read-only. Explicitly selected cartridge GPIO and supported Flash command writes are separate from ROM storage.
Next steps
Follow the general GBA usability roadmap. Prioritize repeatable homebrew gameplay, demonstrated compatibility failures, cartridge saves, and audio. The goal is usable emulation across games, not an Emerald-specific implementation.
The remaining hardware-validation backlog includes:
- Extend shared fetch samples to verified general-bus data-access history and unsupported fetch regions. General DMA open-bus reads and sub-instruction arbitration remain separate from retained channel data and local IWRAM lanes. Keep unknown history diagnostic until fetch ordering and latch ownership have independent coverage. Validate BIOS snapshots with independent hardware tests before claiming exact refill or data-access history. The desktop runner still uses only the original BIOS. Keep protected reads image-derived for all supplied images.
- Validate the active nominal Game Pak prefetch queue against independent timing tests. The cancellation probe now matches after ordered timer accesses. The shared timer prescaler now retains a common clock origin across enable and clock-source changes. Validate delayed timer startup/control edges and extend ordered observations to other devices without duplicate clocks or lost rollback. Validate full-buffer restart, page boundaries, live WAITCNT transitions, and cold-start costs. See prefetch behavior and evidence; exact bus arbitration and timer/IRQ delays remain separate work.
- Validate keypad retrigger behavior with hardware tests and add remaining device registers; extend BIOS reset coverage as sound/serial support becomes available. Validate STOP entry/wake edges and add external wake sources and remaining DMA device modes.
- Replace nominal sprite work limits with verified individual fetch timing; add background fetch timing and per-pixel composition.
- Validate more original/public test ROMs through the window. Expand compatibility evidence across independent programs.
Keep the emulator core independent of window and audio libraries. Treat Nintendo DS support as a separate project phase.