feat(cartridge): add bounded terminal ROM loading

Load read-only raw ROM files with bounded size checks and original BIOS boot. Require a machine-step budget and report CPU state, STOP, and explicit diagnostics without opening a window. Keep file access in the desktop crate.

Cover argument parsing, Darwin paths, file boundaries, ARM/Thumb execution, DMA/IRQ budgets, HALT/STOP, and error reports. Document limits and usage. Verified on native Darwin arm64: debug/release workspace tests, core-only tests, Clippy, rustdoc, all ten window smoke tests, and a release raw-ROM run.
This commit is contained in:
0xrsydn 2026-10-05 18:57:16 +07:00
commit c256bf8ccd
13 changed files with 837 additions and 13 deletions

View file

@ -78,7 +78,10 @@ The repository is a Cargo workspace with three crates:
| `crates/desktop/src/desktop/effects.rs` | Window/effects demo and independent smoke-test pixel checks |
| `crates/desktop/src/desktop/mosaic.rs` | Mosaic window and 128-frame independent pixel checks |
| `crates/desktop/src/desktop/raster.rs` | Raster window and scanline color-band smoke test |
| `crates/desktop/src/main.rs` | Command-line modes and fixed-length CPU demo |
| `crates/desktop/src/main.rs` | Command-line modes, error exit status, and fixed-length CPU demo |
| `crates/desktop/src/cartridge.rs` | Read-only ROM files, argument checks, bounded machine execution, and terminal reports |
| `crates/desktop/src/cartridge/tests.rs` | ROM options, bounded readers, instruction/DMA/IRQ budgets, HALT/STOP, and diagnostic reports |
| `crates/desktop/tests/rom_cli.rs` | Process-level loading and exit-status checks using temporary original programs |
| `crates/gba-core/tests/core.rs` | CPU integration tests and the complete demo |
| `crates/gba-core/tests/memory.rs` | Memory widths, alignment, errors, and mirrors |
| `crates/gba-core/tests/exceptions.rs` | Exception demo, BIOS mapping, and reset-vector execution |

View file

@ -17,6 +17,7 @@ Verified locally on macOS 15.7.3:
- All ten native window smoke tests pass. The mosaic test submits 128 frames; the other nine submit 60 frames each.
- The eight CPU-driven smoke tests check CPU state, every output pixel, and presentation at VBlank entry.
- The terminal-only CPU and timer IRQ demos run successfully.
- The bounded ROM runner loads original raw programs and reports state without opening a window.
These results cover the CPU core, memory, Mode 0–5 snapshots and row capture, input mapping, and desktop windows.
They do not verify a complete GBA display controller or audio.

View file

@ -26,7 +26,8 @@ Minimal boot initializes:
It then enters `0x08000000` in ARM System mode with IRQ/FIQ masks clear.
It does not reproduce Nintendo's logo, cartridge-header checks, RAM clearing, boot delays, or full hardware initialization.
The executable still does not load game files.
The executable can load raw ROM files for [bounded terminal diagnostics](cartridge.md) using this boot sequence.
This does not establish game compatibility or complete BIOS behavior.
Supported software interrupt services:

View file

@ -0,0 +1,64 @@
# Cartridge files and terminal execution
The desktop executable can load raw ROM bytes and run a bounded diagnostic session.
This supports original test programs. It does not establish commercial-game compatibility.
```sh
direnv exec . cargo run --locked --release -- --rom path/to/original.gba --steps 100000
```
Both options are required. Their order does not matter.
`COUNT` must contain decimal digits and be between 1 and 100,000,000 inclusive.
Do not combine ROM mode with demo or help options. Bare file paths are not accepted.
Quote paths that contain spaces. File extensions do not affect loading.
## Loading and boot
`crates/desktop/src/cartridge.rs` owns file access, argument checks, execution limits, and reports.
The core remains independent of the filesystem and window library.
The loader opens a regular file read-only and accepts 4 bytes through 32 MiB inclusive.
It checks metadata before and after opening, then independently bounds the read to the limit plus one byte.
This bounds file content reads even if the file grows. It is not a filesystem race protection mechanism.
Directories and other non-regular files are rejected. Symlinks to regular files are accepted.
Paths retain their operating-system representation and appear quoted in diagnostics.
The host filesystem can reject filenames, including invalid UTF-8 on Darwin.
Bytes are not padded, patched, or written back.
The loader does not validate a cartridge header, logo, or checksum.
It does not decode archives or ELF executables. Supply a raw binary with an ARM instruction at offset zero.
Headerless original programs are accepted.
Reads past supplied cartridge bytes remain explicit memory errors, not open-bus values.
All three Game Pak ROM windows use the same supplied bytes and existing wait-state rules.
Cartridge writes, save devices, and cartridge peripherals remain unsupported.
The runner calls `bios::boot` with the loaded bytes.
The [original BIOS replacement](bios.md) executes its minimal boot before entering `0x08000000` in ARM System mode.
There is no command-line option for external BIOS files.
Unsupported services remain diagnostics. In particular, RegisterRamReset sound/serial flags, including `r0=0xff`, still fail.
## Execution limits and results
The budget counts successful machine steps, including BIOS boot instructions.
Each CPU instruction, IRQ entry, DMA unit, or HALT idle batch consumes one step.
The budget is not an instruction-only, cycle, frame, or wall-clock limit.
HALT continues advancing devices within the budget.
STOP returns immediately because terminal mode has no input source to wake the machine.
STOP on the final allowed step is reported as STOP, not as budget exhaustion.
A failed CPU or DMA step consumes no budget and retains the machine state from earlier successful steps.
The report includes:
- Quoted path, byte count, and requested step limit.
- Stop reason and successful-step counters by kind.
- Nominal emulated cycles, PC, CPSR, CPU mode, and ARM/Thumb state.
- HALT/STOP flags and all active registers r0–r15.
Exit status zero means the step limit was reached or STOP was entered.
It does not mean the program completed or passed a hardware test.
Invalid arguments, loading failures, output failures, and emulation diagnostics produce a nonzero exit status.
For emulation diagnostics, stdout contains the final machine state and stderr contains the core error.
ROM mode has no window, keyboard input, audio, saves, per-step trace, or real-time pacing.
It does not enable frame capture or validate rendered output.
Use the existing demos for window and input tests.
Only load files that you may lawfully use. Do not commit game ROMs or firmware.

View file

@ -62,6 +62,7 @@ Update this file when a feature lands or a limit is removed.
- `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.
- Raw ROM-file loading for bounded terminal diagnostics, with original BIOS boot and final CPU/step reports.
- 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.
@ -102,7 +103,9 @@ Keypad IRQs use a documented polling model; hardware retrigger edges and asynchr
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.
The executable does not accept ROM files yet.
ROM files can run in bounded terminal mode with the original BIOS replacement.
This mode has no window, input, audio, saves, or external BIOS option. It does not establish commercial-game compatibility.
See [cartridge loading](hardware/cartridge.md) for file limits, step budgets, and exit status.
Unmapped reads return errors instead of hardware open-bus values.
Reads beyond the supplied cartridge bytes also return errors.
@ -117,7 +120,7 @@ Writes to cartridge addresses return errors instead of modeling cartridge hardwa
3. 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.
4. Replace nominal sprite work limits with verified individual fetch timing; add background fetch timing and per-pixel composition.
5. Expand graphics, audio, cartridge loading, and saves before testing Emerald compatibility.
5. Connect ROM execution to the window and input; expand audio, cartridge hardware, and saves before testing Emerald compatibility.
Keep the emulator core independent of window and audio libraries.
Treat Nintendo DS support as a separate project phase.

View file

@ -37,6 +37,13 @@ The core's integration tests use `gba-demos` as a development dependency.
On Apple Silicon, `file` must report a Mach-O `arm64` executable.
Do not set a Linux cross-compilation target for this validation.
ROM-runner tests use temporary files containing original instructions, without Nintendo assets or a desktop session.
They check file-size boundaries, bounded reads, short reads, I/O errors, paths, symlinks, and read-only loading.
CLI tests cover option order, missing/conflicting options, invalid step limits, process exit status, and reports.
Execution tests cover original ARM/Thumb code, BIOS boot, DMA/IRQ step accounting, HALT budgets, and prompt STOP results.
Unsupported instructions, truncated code, and DMA errors retain the failure state for inspection.
See [cartridge execution](hardware/cartridge.md) for usage and limitations.
Angle-service tests compare results with wide-integer polynomial and signed-sector references, plus floating-point accuracy checks in supported ranges.
They cover a dense ArcTan unit-interval grid, sampled full-domain and seeded inputs, axes, quadrant boundaries, signed extremes, and scale invariance.
Other tests verify all caller flag combinations, User/System masks, non-result registers, stack bounds, repeated calls, diagnostics, and DMA/IRQ progress.