refactor: split into gameboy-rust workspace with core, demos, and desktop crates
Move the emulator into crates/gba-core, the original demo programs into crates/gba-demos, and the minifb frontend into crates/desktop. The binary is now gameboy-rust. Imports change from gba_rust to gba_core/gba_demos; no behavior changes. gba-core has no dependencies. Its integration tests use gba-demos as a development dependency. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a8944d1d5f
commit
f8a0676748
113 changed files with 304 additions and 282 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
|
@ -141,12 +141,28 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "gba-rust"
|
||||
name = "gameboy-rust-desktop"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gba-core",
|
||||
"gba-demos",
|
||||
"minifb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gba-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gba-demos",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gba-demos"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gba-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
|
|
|
|||
20
Cargo.toml
20
Cargo.toml
|
|
@ -1,18 +1,8 @@
|
|||
[package]
|
||||
name = "gba-rust"
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["crates/gba-core", "crates/gba-demos", "crates/desktop"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[features]
|
||||
default = ["desktop"]
|
||||
desktop = ["dep:minifb"]
|
||||
|
||||
[dependencies]
|
||||
# Pinned because src/desktop.rs corrects a macOS focus bug in this version.
|
||||
minifb = { version = "=0.28.0", optional = true, default-features = false, features = ["x11"] }
|
||||
|
||||
[[bin]]
|
||||
name = "gba-rust"
|
||||
path = "src/main.rs"
|
||||
required-features = ["desktop"]
|
||||
|
|
|
|||
242
README.md
242
README.md
|
|
@ -1,8 +1,11 @@
|
|||
# gba-rust
|
||||
# gameboy-rust
|
||||
|
||||
A small Game Boy Advance (GBA) emulator foundation written in Rust.
|
||||
The core has no external Rust dependencies when built with `--no-default-features`.
|
||||
The default `desktop` feature adds minifb for a native window.
|
||||
Game Boy family emulation in Rust. The Game Boy Advance (GBA) is the first and currently only system.
|
||||
This is a small GBA emulator foundation, organized as a Cargo workspace:
|
||||
|
||||
- `crates/gba-core`: the platform-independent emulator, with no external Rust dependencies.
|
||||
- `crates/gba-demos`: original test programs that drive the core.
|
||||
- `crates/desktop`: the native window frontend, built on minifb. It provides the `gameboy-rust` executable.
|
||||
|
||||
**This cannot run Pokémon Emerald or other games yet.**
|
||||
The CPU-driven demos run original ARM code through emulated video RAM.
|
||||
|
|
@ -279,7 +282,7 @@ From this project directory:
|
|||
direnv allow
|
||||
cargo run
|
||||
cargo test
|
||||
cargo fmt --check
|
||||
cargo fmt --all --check
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
```
|
||||
|
||||
|
|
@ -303,7 +306,7 @@ The flake sets Darwin-only `CFLAGS` to correct two minifb 0.28 native-build issu
|
|||
|
||||
Build through direnv or `nix develop` so these settings apply.
|
||||
The window runs on the main thread, as required by macOS AppKit.
|
||||
`src/desktop.rs` also corrects the inverted macOS focus result in minifb 0.28.0.
|
||||
`crates/desktop/src/desktop.rs` also corrects the inverted macOS focus result in minifb 0.28.0.
|
||||
The dependency is pinned to that exact version. Review this workaround before upgrading minifb.
|
||||
Intel macOS and Linux desktop builds are not verified.
|
||||
|
||||
|
|
@ -477,7 +480,7 @@ Neither constructor provides Nintendo BIOS services or initializes BIOS-managed
|
|||
|
||||
### Optional original BIOS replacement
|
||||
|
||||
`src/bios.rs` builds a deterministic 16 KiB image from original ARM instructions and mathematically generated data.
|
||||
`crates/gba-core/src/bios.rs` builds a deterministic 16 KiB image from original ARM instructions and mathematically generated data.
|
||||
No Nintendo firmware bytes are included.
|
||||
A compile-time integer calculation generates the 512-byte sine table at `0x3e00..0x3fff`.
|
||||
The image builder checks that code and literal pools do not overlap this table.
|
||||
|
|
@ -1632,100 +1635,102 @@ Important timing limits:
|
|||
| --- | --- |
|
||||
| `flake.nix`, `flake.lock` | Pinned development environment |
|
||||
| `.envrc` | Automatic environment loading through direnv |
|
||||
| `src/cpu.rs` | Registers, flags, instruction-set state, and stepping |
|
||||
| `src/cpu/arm.rs` | ARM decoding, data processing, transfers, branches, and multiply |
|
||||
| `src/cpu/alu.rs` | Shared arithmetic and barrel shifter |
|
||||
| `src/cpu/transfer.rs` | Shared ARM/Thumb block transfers and ARM swaps |
|
||||
| `src/cpu/thumb.rs` | Thumb decoding and execution |
|
||||
| `src/cpu/status.rs` | Processor modes, register banks, and status transfers |
|
||||
| `src/cpu/exception.rs` | Reset state, exception entry, and interrupt sampling |
|
||||
| `src/cpu/status_tests.rs`, `src/cpu/exception_tests.rs` | Status, banking, exception, and return tests |
|
||||
| `src/cpu/thumb_tests.rs` | Thumb instructions, state switching, and decoder checks |
|
||||
| `src/cpu/transfer_tests.rs` | Stack, addressing, overlap, empty-list, and swap tests |
|
||||
| `src/cpu/tests.rs` | Condition truth tables and immediate arithmetic tests |
|
||||
| `src/cpu/instruction_tests.rs` | Register operations, transfers, branches, and edge cases |
|
||||
| `src/memory.rs` | Memory mapping, I/O routing, write validation, and device clock |
|
||||
| `src/io.rs` | I/O registers, timers, HALT wake-up, next-event bounds, and IRQ latches |
|
||||
| `src/display.rs` | Display clock, scanline status, comparison edges, and display IRQ events |
|
||||
| `src/dma.rs` | DMA registers, internal pointers, trigger state, priority, and completion IRQs |
|
||||
| `src/machine.rs` | Timed CPU/DMA/device stepping and IRQ delivery |
|
||||
| `src/timing.rs` | Bus widths, wait-state costs, and timing breakdowns |
|
||||
| `src/cpu/timing.rs` | ARM/Thumb cycle summaries and data-access accounting |
|
||||
| `src/cpu/timing_tests.rs` | Instruction timing and semantic-equivalence checks |
|
||||
| `src/timer_demo.rs` | Original timer-configuration program and IRQ handler |
|
||||
| `src/lib.rs` | Core modules and original demo bytes |
|
||||
| `src/bios.rs` | Original ARM BIOS image builder, minimal boot, IRQ dispatch, waits, and memory services |
|
||||
| `src/bios/reset.rs` | Emitted ARM SoftReset and selective RegisterRamReset; CPU banks, RAM clearing, and supported device-register resets |
|
||||
| `src/bios/arithmetic.rs` | Emitted ARM division and integer-square-root routines |
|
||||
| `src/bios/affine.rs` | Emitted ARM background/sprite matrix services, range checks, and generated sine table |
|
||||
| `src/bios/angles.rs` | Emitted ARM ArcTan polynomial, ArcTan2 ratio/quadrant handling, and input validation |
|
||||
| `src/bios/lz77.rs` | Emitted ARM LZ77 decoder with byte and halfword output |
|
||||
| `src/bios/run_length.rs` | Emitted ARM run-length decoder, header validation, and block bounds |
|
||||
| `src/bios/bit_unpack.rs` | Emitted ARM packed-unit expansion, offsets, word stores, and validation |
|
||||
| `src/bios/decompression.rs` | Shared emitted byte/halfword output routine for decompression and byte differential filters |
|
||||
| `src/bios/differential.rs` | Emitted ARM byte/halfword differential filters, modular accumulation, and validation |
|
||||
| `src/bios/huffman.rs` | Emitted ARM Huffman tree traversal, symbol packing, word output, and validation |
|
||||
| `src/video.rs` | Presentation buffer, RGB555 conversion, and Mode 0–5 composition |
|
||||
| `src/video/affine.rs` | Programmed registers, internal scanline origins, and tiled/bitmap sampling |
|
||||
| `src/video/windows.rs` | Persistent vertical window edge flags and constant-time clock advancement |
|
||||
| `src/video/windows/horizontal.rs` | Horizontal comparator flags, per-column history, and bounded bulk advancement |
|
||||
| `src/video/mosaic.rs` | Live vertical mosaic phase and constant-time counter transitions |
|
||||
| `src/video/capture.rs` | Drawing/completed frame buffers, row completeness, and deferred render diagnostics |
|
||||
| `src/video/sprites.rs` | Sprite index preparation, priority metadata, mosaic, late palette lookup, and composition |
|
||||
| `src/video/sprites/pipeline.rs` | Two prepared row buffers, cycle40 events, and bounded capture-disabled advancement |
|
||||
| `src/video/sprites/budget.rs` | Nominal per-row work allowance, partial canvas prefixes, and independent arithmetic tests |
|
||||
| `src/input.rs` | Platform-independent GBA button state |
|
||||
| `src/graphics_demo.rs` | Original ARM bitmap program and shared bounded frame runner |
|
||||
| `src/tile_demo.rs` | Original ARM tile/sprite program, palettes, tiles, maps, and OAM image |
|
||||
| `src/affine_demo.rs` | Shared ARM background program builder and Mode 2 assets |
|
||||
| `src/affine_raster_demo.rs` | CPU-driven HBlank DMA affine distortion demo |
|
||||
| `src/bitmap_demo.rs` | Mode 4/5 demo runners, palettes, and original two-page images |
|
||||
| `src/effects_demo.rs` | CPU-driven window and color-effects demo runner |
|
||||
| `src/mosaic_demo.rs` | CPU-driven background/sprite mosaic demo runner |
|
||||
| `src/raster_demo.rs` | Original ARM HBlank DMA raster program and color table |
|
||||
| `src/video/effects.rs` | Region masks and RGB555 alpha/brightness arithmetic |
|
||||
| `src/desktop.rs` | Native window, display test, and keyboard controls |
|
||||
| `src/desktop/affine.rs` | Affine background window and smoke-test pixel checks |
|
||||
| `src/desktop/affine_raster.rs` | Affine raster window and every-pixel smoke checks |
|
||||
| `src/desktop/bitmap.rs` | Mode 4/5 windows and page-flipping smoke-test pixel checks |
|
||||
| `src/desktop/effects.rs` | Window/effects demo and independent smoke-test pixel checks |
|
||||
| `src/desktop/mosaic.rs` | Mosaic window and 128-frame independent pixel checks |
|
||||
| `src/desktop/raster.rs` | Raster window and scanline color-band smoke test |
|
||||
| `src/main.rs` | Command-line modes and fixed-length CPU demo |
|
||||
| `tests/core.rs` | CPU integration tests and the complete demo |
|
||||
| `tests/memory.rs` | Memory widths, alignment, errors, and mirrors |
|
||||
| `tests/exceptions.rs` | Exception demo, BIOS mapping, and reset-vector execution |
|
||||
| `tests/timers.rs` | Timer rules, interrupt registers, and a cycle-by-cycle reference |
|
||||
| `tests/machine.rs` | Device IRQ entry/return, clock policy, and I/O failure atomicity |
|
||||
| `tests/timing.rs` | WAITCNT fields, bus costs, and timer/IRQ timing integration |
|
||||
| `tests/graphics.rs` | Video memory, rendering, KEYINPUT, and CPU-driven graphics integration |
|
||||
| `tests/tiles.rs` | Mode 0 registers, maps, palettes, composition, diagnostics, and CPU tile/sprite demo |
|
||||
| `tests/affine_backgrounds.rs` | Affine registers, maps, transforms, bitmap sampling, composition, and CPU demo |
|
||||
| `tests/affine_tracking.rs` | Internal origins, mid-frame writes, reloads, mosaic, DMA, and affine raster demo |
|
||||
| `tests/bitmap_modes.rs` | Mode 4/5 pages, formats, transforms, transparency, sprites, and CPU demos |
|
||||
| `tests/effects.rs`, `tests/effects/` | Window masks, color arithmetic, target selection, OBJ effects, DMA, and CPU demo |
|
||||
| `tests/window_tracking.rs`, `tests/window_tracking/` | Vertical/horizontal edges, mid-line writes, hidden positions, DMA, masks, and capture independence |
|
||||
| `tests/mosaic.rs`, `tests/mosaic/` | Mosaic sizes, sampling, transparent metadata, windows, DMA, and CPU demo |
|
||||
| `tests/mosaic_tracking.rs` | Size changes, counter wrap, text/affine/OBJ sampling, DMA, and frame resets |
|
||||
| `tests/scanlines.rs`, `tests/scanlines/` | Capture boundaries, mid-frame changes, DMA ordering, diagnostics, and raster program |
|
||||
| `tests/sprites.rs` | OAM, DMA, sprite sizes, mapping, palettes, flips, clipping, priorities, and diagnostics |
|
||||
| `tests/sprite_pipeline.rs` | Preparation boundaries, OAM/VRAM history, late palette/effects, DMA, row0, and diagnostics |
|
||||
| `tests/sprite_budget.rs` | Regular/affine costs, clipping policy, truncation, inspection, bit5 sampling, DMA, and diagnostics |
|
||||
| `tests/sprites/affine.rs` | Affine matrices, drawing areas, signed sampling, shared groups, and floating-point reference tests |
|
||||
| `tests/display.rs` | Display boundaries, register masks, IRQ handlers, and VBlank frame execution |
|
||||
| `tests/dma.rs` | DMA widths, latches, priority, triggers, IRQs, timing, errors, and CPU integration |
|
||||
| `tests/halt.rs` | HALT wake masks, idle timing, BIOS-only writes, DMA progress, and STOP diagnostics |
|
||||
| `tests/bios.rs` | ARM/Thumb service calls, copy/fill boundaries, wait races, callback contracts, and boot |
|
||||
| `tests/bios/ram_reset.rs` | Selective RAM boundaries, flag combinations, I/O reset, display rendering, DMA/timer latches, and diagnostics |
|
||||
| `tests/bios/reset.rs` | All restart flags, exact RAM boundaries, CPU banks, restart execution, device continuity, and IRQ masking |
|
||||
| `tests/bios/arithmetic.rs` | Arithmetic boundaries, wide-integer references, status restoration, and zero-division diagnostics |
|
||||
| `tests/bios/affine.rs` | Matrix/origin references, all angle phases, strides, live rendering, register preservation, and diagnostics |
|
||||
| `tests/bios/angles.rs` | Fixed-point references, axes/quadrants, rounding, caller flags, stack bounds, DMA, and diagnostics |
|
||||
| `tests/bios/lz77.rs` | Token-reference tests, overlaps, output widths, malformed streams, and partial failures |
|
||||
| `tests/bios/run_length.rs` | All block controls, mixed streams, output widths, status, diagnostics, DMA, and IRQ masking |
|
||||
| `tests/bios/bit_unpack.rs` | Width pairs, bit references, offsets, maximum length, memory boundaries, status, DMA, and diagnostics |
|
||||
| `tests/bios/differential.rs` | Round trips, wraparound, output widths, large lengths, partial failures, status, DMA, and diagnostics |
|
||||
| `tests/bios/huffman.rs` | Independent path encoding, tree bounds, packing, large lengths, partial failures, status, and DMA |
|
||||
| `crates/gba-core/src/cpu.rs` | Registers, flags, instruction-set state, and stepping |
|
||||
| `crates/gba-core/src/cpu/arm.rs` | ARM decoding, data processing, transfers, branches, and multiply |
|
||||
| `crates/gba-core/src/cpu/alu.rs` | Shared arithmetic and barrel shifter |
|
||||
| `crates/gba-core/src/cpu/transfer.rs` | Shared ARM/Thumb block transfers and ARM swaps |
|
||||
| `crates/gba-core/src/cpu/thumb.rs` | Thumb decoding and execution |
|
||||
| `crates/gba-core/src/cpu/status.rs` | Processor modes, register banks, and status transfers |
|
||||
| `crates/gba-core/src/cpu/exception.rs` | Reset state, exception entry, and interrupt sampling |
|
||||
| `crates/gba-core/src/cpu/status_tests.rs`, `crates/gba-core/src/cpu/exception_tests.rs` | Status, banking, exception, and return tests |
|
||||
| `crates/gba-core/src/cpu/thumb_tests.rs` | Thumb instructions, state switching, and decoder checks |
|
||||
| `crates/gba-core/src/cpu/transfer_tests.rs` | Stack, addressing, overlap, empty-list, and swap tests |
|
||||
| `crates/gba-core/src/cpu/tests.rs` | Condition truth tables and immediate arithmetic tests |
|
||||
| `crates/gba-core/src/cpu/instruction_tests.rs` | Register operations, transfers, branches, and edge cases |
|
||||
| `crates/gba-core/src/memory.rs` | Memory mapping, I/O routing, write validation, and device clock |
|
||||
| `crates/gba-core/src/io.rs` | I/O registers, timers, HALT wake-up, next-event bounds, and IRQ latches |
|
||||
| `crates/gba-core/src/display.rs` | Display clock, scanline status, comparison edges, and display IRQ events |
|
||||
| `crates/gba-core/src/dma.rs` | DMA registers, internal pointers, trigger state, priority, and completion IRQs |
|
||||
| `crates/gba-core/src/machine.rs` | Timed CPU/DMA/device stepping and IRQ delivery |
|
||||
| `crates/gba-core/src/timing.rs` | Bus widths, wait-state costs, and timing breakdowns |
|
||||
| `crates/gba-core/src/cpu/timing.rs` | ARM/Thumb cycle summaries and data-access accounting |
|
||||
| `crates/gba-core/src/cpu/timing_tests.rs` | Instruction timing and semantic-equivalence checks |
|
||||
| `crates/gba-demos/src/timer_demo.rs` | Original timer-configuration program and IRQ handler |
|
||||
| `Cargo.toml` | Workspace members and shared package settings |
|
||||
| `crates/gba-core/src/lib.rs` | Core modules |
|
||||
| `crates/gba-demos/src/lib.rs` | Demo modules and original instruction/exception demo bytes |
|
||||
| `crates/gba-core/src/bios.rs` | Original ARM BIOS image builder, minimal boot, IRQ dispatch, waits, and memory services |
|
||||
| `crates/gba-core/src/bios/reset.rs` | Emitted ARM SoftReset and selective RegisterRamReset; CPU banks, RAM clearing, and supported device-register resets |
|
||||
| `crates/gba-core/src/bios/arithmetic.rs` | Emitted ARM division and integer-square-root routines |
|
||||
| `crates/gba-core/src/bios/affine.rs` | Emitted ARM background/sprite matrix services, range checks, and generated sine table |
|
||||
| `crates/gba-core/src/bios/angles.rs` | Emitted ARM ArcTan polynomial, ArcTan2 ratio/quadrant handling, and input validation |
|
||||
| `crates/gba-core/src/bios/lz77.rs` | Emitted ARM LZ77 decoder with byte and halfword output |
|
||||
| `crates/gba-core/src/bios/run_length.rs` | Emitted ARM run-length decoder, header validation, and block bounds |
|
||||
| `crates/gba-core/src/bios/bit_unpack.rs` | Emitted ARM packed-unit expansion, offsets, word stores, and validation |
|
||||
| `crates/gba-core/src/bios/decompression.rs` | Shared emitted byte/halfword output routine for decompression and byte differential filters |
|
||||
| `crates/gba-core/src/bios/differential.rs` | Emitted ARM byte/halfword differential filters, modular accumulation, and validation |
|
||||
| `crates/gba-core/src/bios/huffman.rs` | Emitted ARM Huffman tree traversal, symbol packing, word output, and validation |
|
||||
| `crates/gba-core/src/video.rs` | Presentation buffer, RGB555 conversion, and Mode 0–5 composition |
|
||||
| `crates/gba-core/src/video/affine.rs` | Programmed registers, internal scanline origins, and tiled/bitmap sampling |
|
||||
| `crates/gba-core/src/video/windows.rs` | Persistent vertical window edge flags and constant-time clock advancement |
|
||||
| `crates/gba-core/src/video/windows/horizontal.rs` | Horizontal comparator flags, per-column history, and bounded bulk advancement |
|
||||
| `crates/gba-core/src/video/mosaic.rs` | Live vertical mosaic phase and constant-time counter transitions |
|
||||
| `crates/gba-core/src/video/capture.rs` | Drawing/completed frame buffers, row completeness, and deferred render diagnostics |
|
||||
| `crates/gba-core/src/video/sprites.rs` | Sprite index preparation, priority metadata, mosaic, late palette lookup, and composition |
|
||||
| `crates/gba-core/src/video/sprites/pipeline.rs` | Two prepared row buffers, cycle40 events, and bounded capture-disabled advancement |
|
||||
| `crates/gba-core/src/video/sprites/budget.rs` | Nominal per-row work allowance, partial canvas prefixes, and independent arithmetic tests |
|
||||
| `crates/gba-core/src/input.rs` | Platform-independent GBA button state |
|
||||
| `crates/gba-demos/src/graphics_demo.rs` | Original ARM bitmap program and shared bounded frame runner |
|
||||
| `crates/gba-demos/src/tile_demo.rs` | Original ARM tile/sprite program, palettes, tiles, maps, and OAM image |
|
||||
| `crates/gba-demos/src/affine_demo.rs` | Shared ARM background program builder and Mode 2 assets |
|
||||
| `crates/gba-demos/src/affine_raster_demo.rs` | CPU-driven HBlank DMA affine distortion demo |
|
||||
| `crates/gba-demos/src/bitmap_demo.rs` | Mode 4/5 demo runners, palettes, and original two-page images |
|
||||
| `crates/gba-demos/src/effects_demo.rs` | CPU-driven window and color-effects demo runner |
|
||||
| `crates/gba-demos/src/mosaic_demo.rs` | CPU-driven background/sprite mosaic demo runner |
|
||||
| `crates/gba-demos/src/raster_demo.rs` | Original ARM HBlank DMA raster program and color table |
|
||||
| `crates/gba-core/src/video/effects.rs` | Region masks and RGB555 alpha/brightness arithmetic |
|
||||
| `crates/desktop/src/desktop.rs` | Native window, display test, and keyboard controls |
|
||||
| `crates/desktop/src/desktop/affine.rs` | Affine background window and smoke-test pixel checks |
|
||||
| `crates/desktop/src/desktop/affine_raster.rs` | Affine raster window and every-pixel smoke checks |
|
||||
| `crates/desktop/src/desktop/bitmap.rs` | Mode 4/5 windows and page-flipping smoke-test pixel checks |
|
||||
| `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/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 |
|
||||
| `crates/gba-core/tests/timers.rs` | Timer rules, interrupt registers, and a cycle-by-cycle reference |
|
||||
| `crates/gba-core/tests/machine.rs` | Device IRQ entry/return, clock policy, and I/O failure atomicity |
|
||||
| `crates/gba-core/tests/timing.rs` | WAITCNT fields, bus costs, and timer/IRQ timing integration |
|
||||
| `crates/gba-core/tests/graphics.rs` | Video memory, rendering, KEYINPUT, and CPU-driven graphics integration |
|
||||
| `crates/gba-core/tests/tiles.rs` | Mode 0 registers, maps, palettes, composition, diagnostics, and CPU tile/sprite demo |
|
||||
| `crates/gba-core/tests/affine_backgrounds.rs` | Affine registers, maps, transforms, bitmap sampling, composition, and CPU demo |
|
||||
| `crates/gba-core/tests/affine_tracking.rs` | Internal origins, mid-frame writes, reloads, mosaic, DMA, and affine raster demo |
|
||||
| `crates/gba-core/tests/bitmap_modes.rs` | Mode 4/5 pages, formats, transforms, transparency, sprites, and CPU demos |
|
||||
| `crates/gba-core/tests/effects.rs`, `crates/gba-core/tests/effects/` | Window masks, color arithmetic, target selection, OBJ effects, DMA, and CPU demo |
|
||||
| `crates/gba-core/tests/window_tracking.rs`, `crates/gba-core/tests/window_tracking/` | Vertical/horizontal edges, mid-line writes, hidden positions, DMA, masks, and capture independence |
|
||||
| `crates/gba-core/tests/mosaic.rs`, `crates/gba-core/tests/mosaic/` | Mosaic sizes, sampling, transparent metadata, windows, DMA, and CPU demo |
|
||||
| `crates/gba-core/tests/mosaic_tracking.rs` | Size changes, counter wrap, text/affine/OBJ sampling, DMA, and frame resets |
|
||||
| `crates/gba-core/tests/scanlines.rs`, `crates/gba-core/tests/scanlines/` | Capture boundaries, mid-frame changes, DMA ordering, diagnostics, and raster program |
|
||||
| `crates/gba-core/tests/sprites.rs` | OAM, DMA, sprite sizes, mapping, palettes, flips, clipping, priorities, and diagnostics |
|
||||
| `crates/gba-core/tests/sprite_pipeline.rs` | Preparation boundaries, OAM/VRAM history, late palette/effects, DMA, row0, and diagnostics |
|
||||
| `crates/gba-core/tests/sprite_budget.rs` | Regular/affine costs, clipping policy, truncation, inspection, bit5 sampling, DMA, and diagnostics |
|
||||
| `crates/gba-core/tests/sprites/affine.rs` | Affine matrices, drawing areas, signed sampling, shared groups, and floating-point reference tests |
|
||||
| `crates/gba-core/tests/display.rs` | Display boundaries, register masks, IRQ handlers, and VBlank frame execution |
|
||||
| `crates/gba-core/tests/dma.rs` | DMA widths, latches, priority, triggers, IRQs, timing, errors, and CPU integration |
|
||||
| `crates/gba-core/tests/halt.rs` | HALT wake masks, idle timing, BIOS-only writes, DMA progress, and STOP diagnostics |
|
||||
| `crates/gba-core/tests/bios.rs` | ARM/Thumb service calls, copy/fill boundaries, wait races, callback contracts, and boot |
|
||||
| `crates/gba-core/tests/bios/ram_reset.rs` | Selective RAM boundaries, flag combinations, I/O reset, display rendering, DMA/timer latches, and diagnostics |
|
||||
| `crates/gba-core/tests/bios/reset.rs` | All restart flags, exact RAM boundaries, CPU banks, restart execution, device continuity, and IRQ masking |
|
||||
| `crates/gba-core/tests/bios/arithmetic.rs` | Arithmetic boundaries, wide-integer references, status restoration, and zero-division diagnostics |
|
||||
| `crates/gba-core/tests/bios/affine.rs` | Matrix/origin references, all angle phases, strides, live rendering, register preservation, and diagnostics |
|
||||
| `crates/gba-core/tests/bios/angles.rs` | Fixed-point references, axes/quadrants, rounding, caller flags, stack bounds, DMA, and diagnostics |
|
||||
| `crates/gba-core/tests/bios/lz77.rs` | Token-reference tests, overlaps, output widths, malformed streams, and partial failures |
|
||||
| `crates/gba-core/tests/bios/run_length.rs` | All block controls, mixed streams, output widths, status, diagnostics, DMA, and IRQ masking |
|
||||
| `crates/gba-core/tests/bios/bit_unpack.rs` | Width pairs, bit references, offsets, maximum length, memory boundaries, status, DMA, and diagnostics |
|
||||
| `crates/gba-core/tests/bios/differential.rs` | Round trips, wraparound, output widths, large lengths, partial failures, status, DMA, and diagnostics |
|
||||
| `crates/gba-core/tests/bios/huffman.rs` | Independent path encoding, tree bounds, packing, large lengths, partial failures, status, and DMA |
|
||||
|
||||
## Deliberate limits
|
||||
|
||||
|
|
@ -1765,35 +1770,36 @@ Writes to cartridge addresses return errors instead of modeling cartridge hardwa
|
|||
Run native macOS validation from the project directory:
|
||||
|
||||
```sh
|
||||
direnv exec . cargo fmt --check
|
||||
direnv exec . cargo fmt --all --check
|
||||
direnv exec . cargo clippy --locked --all-targets -- -D warnings
|
||||
direnv exec . cargo test --locked
|
||||
direnv exec . cargo test --locked --release
|
||||
direnv exec . cargo build --locked --release
|
||||
file target/release/gba-rust
|
||||
./target/release/gba-rust --smoke-test
|
||||
./target/release/gba-rust --graphics-smoke-test
|
||||
./target/release/gba-rust --tile-smoke-test
|
||||
./target/release/gba-rust --affine-smoke-test
|
||||
./target/release/gba-rust --affine-raster-smoke-test
|
||||
./target/release/gba-rust --bitmap4-smoke-test
|
||||
./target/release/gba-rust --bitmap5-smoke-test
|
||||
./target/release/gba-rust --effects-smoke-test
|
||||
./target/release/gba-rust --mosaic-smoke-test
|
||||
./target/release/gba-rust --raster-smoke-test
|
||||
./target/release/gba-rust --cpu-demo
|
||||
./target/release/gba-rust --timer-demo
|
||||
file target/release/gameboy-rust
|
||||
./target/release/gameboy-rust --smoke-test
|
||||
./target/release/gameboy-rust --graphics-smoke-test
|
||||
./target/release/gameboy-rust --tile-smoke-test
|
||||
./target/release/gameboy-rust --affine-smoke-test
|
||||
./target/release/gameboy-rust --affine-raster-smoke-test
|
||||
./target/release/gameboy-rust --bitmap4-smoke-test
|
||||
./target/release/gameboy-rust --bitmap5-smoke-test
|
||||
./target/release/gameboy-rust --effects-smoke-test
|
||||
./target/release/gameboy-rust --mosaic-smoke-test
|
||||
./target/release/gameboy-rust --raster-smoke-test
|
||||
./target/release/gameboy-rust --cpu-demo
|
||||
./target/release/gameboy-rust --timer-demo
|
||||
```
|
||||
|
||||
All ten window smoke tests need an active desktop session. Ordinary tests do not open windows.
|
||||
CPU-driven smoke tests supply scripted buttons; they do not validate physical keyboard events.
|
||||
To test the core without building the window dependency:
|
||||
To test the core and demo programs without building the window dependency:
|
||||
|
||||
```sh
|
||||
direnv exec . cargo test --locked --no-default-features
|
||||
direnv exec . cargo test --locked -p gba-core -p gba-demos
|
||||
```
|
||||
|
||||
This runs 709 core and integration tests; the eleven desktop and command-line tests are excluded.
|
||||
This runs 709 core, demo, and integration tests; the eleven desktop and command-line tests are excluded.
|
||||
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.
|
||||
|
|
|
|||
15
crates/desktop/Cargo.toml
Normal file
15
crates/desktop/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "gameboy-rust-desktop"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "gameboy-rust"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
gba-core = { path = "../gba-core" }
|
||||
gba-demos = { path = "../gba-demos" }
|
||||
# Pinned because src/desktop.rs corrects a macOS focus bug in this version.
|
||||
minifb = { version = "=0.28.0", default-features = false, features = ["x11"] }
|
||||
|
|
@ -19,13 +19,15 @@ use std::{
|
|||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME, VISIBLE_LINES},
|
||||
graphics_demo::{GraphicsDemo, BACKGROUND, DEMO_STATE, SQUARE_SIZE},
|
||||
input::{Button, Buttons},
|
||||
tile_demo::{TileDemo, TILE_STATE},
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::{
|
||||
graphics_demo::{GraphicsDemo, BACKGROUND, DEMO_STATE, SQUARE_SIZE},
|
||||
tile_demo::{TileDemo, TILE_STATE},
|
||||
};
|
||||
use minifb::{Key, KeyRepeat, Scale, Window, WindowOptions};
|
||||
|
||||
const TITLE: &str =
|
||||
|
|
@ -381,14 +383,14 @@ fn validate_tile_smoke(
|
|||
if memory.read32(TILE_STATE)? != index as u32 + 1
|
||||
|| memory.read32(TILE_STATE + 4)? != sx as u32
|
||||
|| memory.read32(TILE_STATE + 8)? != sy as u32
|
||||
|| memory.read16(gba_rust::memory::OAM_START)? != if affine { 0x340 } else { 72 }
|
||||
|| memory.read16(gba_rust::memory::OAM_START + 2)?
|
||||
|| memory.read16(gba_core::memory::OAM_START)? != if affine { 0x340 } else { 72 }
|
||||
|| memory.read16(gba_core::memory::OAM_START + 2)?
|
||||
!= if affine {
|
||||
0x4068
|
||||
} else {
|
||||
0x4070 | if flipped { 0x1000 } else { 0 }
|
||||
}
|
||||
|| memory.read16(gba_rust::memory::OAM_START + 4)? != if behind { 0x400 } else { 0 }
|
||||
|| memory.read16(gba_core::memory::OAM_START + 4)? != if behind { 0x400 } else { 0 }
|
||||
|| u32::from(position.scanline) != VISIBLE_LINES
|
||||
|| u32::from(position.line_cycle) >= demo.machine().last_timing().total()
|
||||
{
|
||||
|
|
@ -397,7 +399,7 @@ fn validate_tile_smoke(
|
|||
);
|
||||
}
|
||||
for (i, value) in matrix.into_iter().enumerate() {
|
||||
if memory.read16(gba_rust::memory::OAM_START + 6 + i as u32 * 8)? != value as u16 {
|
||||
if memory.read16(gba_core::memory::OAM_START + 6 + i as u32 * 8)? != value as u16 {
|
||||
return Err(io::Error::other("tile smoke test: unexpected affine matrix").into());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use super::{create_window, read_buttons};
|
||||
use gba_rust::{
|
||||
affine_demo::{AffineDemo, AFFINE_STATE},
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME, VISIBLE_LINES},
|
||||
input::{Button, Buttons},
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::affine_demo::{AffineDemo, AFFINE_STATE};
|
||||
use minifb::Key;
|
||||
use std::{
|
||||
error::Error,
|
||||
|
|
@ -75,7 +75,7 @@ fn validate(demo: &AffineDemo, frame: &Framebuffer, index: usize) -> Result<(),
|
|||
if m.read32(AFFINE_STATE)? != index as u32 + 1
|
||||
|| m.read32(AFFINE_STATE + 4)? != pan_x as u32
|
||||
|| m.read32(AFFINE_STATE + 8)? != pan_y as u32
|
||||
|| m.read16(gba_rust::io::BG2CNT)? != if clipped { 0x5000 } else { 0x7000 }
|
||||
|| m.read16(gba_core::io::BG2CNT)? != if clipped { 0x5000 } else { 0x7000 }
|
||||
|| u32::from(position.scanline) != VISIBLE_LINES
|
||||
|| u32::from(position.line_cycle) >= demo.machine().last_timing().total()
|
||||
{
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use super::{create_window, read_buttons};
|
||||
use gba_rust::{
|
||||
affine_raster_demo::{AffineRasterDemo, AFFINE_RASTER_STATE},
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME, VISIBLE_LINES},
|
||||
input::{Button, Buttons},
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::affine_raster_demo::{AffineRasterDemo, AFFINE_RASTER_STATE};
|
||||
use minifb::Key;
|
||||
use std::{
|
||||
error::Error,
|
||||
|
|
@ -79,7 +79,7 @@ fn validate(
|
|||
if m.read32(AFFINE_RASTER_STATE)? != index as u32 + 1
|
||||
|| m.read32(AFFINE_RASTER_STATE + 4)? != pan_x as u32
|
||||
|| m.read32(AFFINE_RASTER_STATE + 8)? != pan_y as u32
|
||||
|| m.read16(gba_rust::io::BG2CNT)? != 0x7000
|
||||
|| m.read16(gba_core::io::BG2CNT)? != 0x7000
|
||||
|| u32::from(position.scanline) != VISIBLE_LINES
|
||||
|| u32::from(position.line_cycle) >= demo.machine().last_timing().total()
|
||||
{
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use super::{create_window, read_buttons};
|
||||
use gba_rust::{
|
||||
bitmap_demo::{BitmapDemo, BitmapMode, BITMAP_STATE},
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME, VISIBLE_LINES},
|
||||
input::{Button, Buttons},
|
||||
io::DISPCNT,
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::bitmap_demo::{BitmapDemo, BitmapMode, BITMAP_STATE};
|
||||
use minifb::Key;
|
||||
use std::{
|
||||
error::Error,
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use super::{create_window, read_buttons};
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME, VISIBLE_LINES},
|
||||
effects_demo::{EffectsDemo, EFFECTS_STATE},
|
||||
input::{Button, Buttons},
|
||||
io::{BLDALPHA, BLDCNT, DISPCNT, WININ, WINOUT},
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::effects_demo::{EffectsDemo, EFFECTS_STATE};
|
||||
use minifb::Key;
|
||||
use std::{
|
||||
error::Error,
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
use super::{create_window, read_buttons};
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME, VISIBLE_LINES},
|
||||
input::{Button, Buttons},
|
||||
io::{BG0CNT, BG1CNT, DISPCNT, MOSAIC},
|
||||
memory::OAM_START,
|
||||
mosaic_demo::{MosaicDemo, MOSAIC_STATE},
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::mosaic_demo::{MosaicDemo, MOSAIC_STATE};
|
||||
use minifb::Key;
|
||||
use std::{
|
||||
error::Error,
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use super::{create_window, read_buttons};
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
display::{CPU_HZ, CYCLES_PER_FRAME},
|
||||
dma::DMA_BASE,
|
||||
input::{Button, Buttons},
|
||||
raster_demo::{RasterDemo, RASTER_STATE},
|
||||
video::{rgb555_to_rgb888, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::raster_demo::{RasterDemo, RASTER_STATE};
|
||||
use minifb::Key;
|
||||
use std::{
|
||||
error::Error,
|
||||
|
|
@ -2,12 +2,14 @@ mod desktop;
|
|||
|
||||
use std::{error::Error, ffi::OsString, io};
|
||||
|
||||
use gba_rust::{
|
||||
bitmap_demo::BitmapMode,
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
demo_bios, demo_program, exception_demo_program,
|
||||
io::{IF, TIMER_BASE},
|
||||
memory::{Memory, ROM_START},
|
||||
};
|
||||
use gba_demos::{
|
||||
bitmap_demo::BitmapMode,
|
||||
demo_bios, demo_program, exception_demo_program,
|
||||
timer_demo::{timer_demo, TIMER_DEMO_STEPS},
|
||||
DEMO_STEPS, EXCEPTION_DEMO_STEPS,
|
||||
};
|
||||
|
|
@ -64,7 +66,7 @@ fn parse_args(args: &[OsString]) -> Result<RunMode, io::Error> {
|
|||
[arg] if arg == "--help" || arg == "-h" => Ok(RunMode::Help),
|
||||
_ => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"usage: gba-rust [--cpu-demo | --timer-demo | --graphics-demo | --smoke-test | --graphics-smoke-test | --raster-demo | --raster-smoke-test | --mosaic-demo | --mosaic-smoke-test | --effects-demo | --effects-smoke-test | --tile-demo | --tile-smoke-test | --affine-demo | --affine-smoke-test | --affine-raster-demo | --affine-raster-smoke-test | --bitmap4-demo | --bitmap5-demo | --bitmap4-smoke-test | --bitmap5-smoke-test | --help]; ROM loading is not supported yet",
|
||||
"usage: gameboy-rust [--cpu-demo | --timer-demo | --graphics-demo | --smoke-test | --graphics-smoke-test | --raster-demo | --raster-smoke-test | --mosaic-demo | --mosaic-smoke-test | --effects-demo | --effects-smoke-test | --tile-demo | --tile-smoke-test | --affine-demo | --affine-smoke-test | --affine-raster-demo | --affine-raster-smoke-test | --bitmap4-demo | --bitmap5-demo | --bitmap4-smoke-test | --bitmap5-smoke-test | --help]; ROM loading is not supported yet",
|
||||
)),
|
||||
}
|
||||
}
|
||||
9
crates/gba-core/Cargo.toml
Normal file
9
crates/gba-core/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "gba-core"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
# Integration tests exercise the core through the original demo programs.
|
||||
gba-demos = { path = "../gba-demos" }
|
||||
12
crates/gba-core/src/lib.rs
Normal file
12
crates/gba-core/src/lib.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//! An educational GBA starting point, not a game-compatible emulator.
|
||||
|
||||
pub mod bios;
|
||||
pub mod cpu;
|
||||
pub mod display;
|
||||
pub mod dma;
|
||||
pub mod input;
|
||||
pub mod io;
|
||||
pub mod machine;
|
||||
pub mod memory;
|
||||
pub mod timing;
|
||||
pub mod video;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::*,
|
||||
memory::{Memory, MemoryError, OAM_START as OAM, PALETTE_START as PAL, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888, Framebuffer, VideoError, WIDTH},
|
||||
|
|
@ -281,10 +281,8 @@ fn diagnostics_leave_output_unchanged_and_disabled_layers_skip_validation() {
|
|||
|
||||
#[test]
|
||||
fn cpu_demo_pans_rotates_zooms_clips_cancels_opposites_and_resets() {
|
||||
use gba_rust::{
|
||||
affine_demo::{AffineDemo, AFFINE_STATE},
|
||||
input::{Button, Buttons},
|
||||
};
|
||||
use gba_core::input::{Button, Buttons};
|
||||
use gba_demos::affine_demo::{AffineDemo, AFFINE_STATE};
|
||||
let mut demo = AffineDemo::new().unwrap();
|
||||
let mut f = Framebuffer::default();
|
||||
assert_eq!(demo.machine().memory().read16(DISPCNT).unwrap(), 0);
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use gba_rust::{
|
||||
affine_raster_demo::{AffineRasterDemo, AFFINE_RASTER_STATE, AFFINE_RASTER_TABLE},
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
display::{CYCLES_PER_FRAME, CYCLES_PER_LINE as LINE, HBLANK_START as HB, VBLANK_START as VB},
|
||||
dma::DMA_BASE,
|
||||
|
|
@ -9,6 +8,7 @@ use gba_rust::{
|
|||
memory::{Memory, PALETTE_START as PAL, ROM_START, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888 as rgb, Framebuffer, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::affine_raster_demo::{AffineRasterDemo, AFFINE_RASTER_STATE, AFFINE_RASTER_TABLE};
|
||||
|
||||
fn color(x: u32, y: u32) -> u16 {
|
||||
((x & 31) | ((y & 31) << 5) | (((x + y) & 31) << 10)) as u16
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
bios::{self, IRQ_FLAGS, IRQ_HANDLER, SYSTEM_STACK, UNSUPPORTED_TRAP},
|
||||
cpu::{CpuError, InstructionSet, Mode},
|
||||
display::VBLANK_START,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
bios::INVALID_ARGUMENT_TRAP,
|
||||
dma::DMA_BASE,
|
||||
io::{BG2PA, DISPCNT},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{bios::INVALID_ARGUMENT_TRAP, dma::DMA_BASE};
|
||||
use gba_core::{bios::INVALID_ARGUMENT_TRAP, dma::DMA_BASE};
|
||||
|
||||
/// Wide-integer reference for signed low-word multiplication and floor division.
|
||||
/// This avoids both host signed overflow and the emitted instruction sequence.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::bios::INVALID_ARGUMENT_TRAP;
|
||||
use gba_core::bios::INVALID_ARGUMENT_TRAP;
|
||||
|
||||
fn divide(number: i32, denominator: i32, thumb: bool, service: u8) {
|
||||
let inputs = if service == 6 {
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
bios::INVALID_ARGUMENT_TRAP,
|
||||
dma::DMA_BASE,
|
||||
memory::{OAM_START, PALETTE_START},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{bios::INVALID_ARGUMENT_TRAP, dma::DMA_BASE, memory::OAM_START};
|
||||
use gba_core::{bios::INVALID_ARGUMENT_TRAP, dma::DMA_BASE, memory::OAM_START};
|
||||
|
||||
fn filtered(service: u8, samples: &[u16]) -> (Vec<u8>, Vec<u8>) {
|
||||
let halfword = service == 0x18;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
bios::INVALID_ARGUMENT_TRAP,
|
||||
dma::DMA_BASE,
|
||||
memory::{OAM_START, PALETTE_START},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::bios::INVALID_ARGUMENT_TRAP;
|
||||
use gba_core::bios::INVALID_ARGUMENT_TRAP;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Token {
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
bios::INVALID_ARGUMENT_TRAP,
|
||||
dma::{DmaError, DMA_BASE, DMA_STRIDE},
|
||||
input::Buttons,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
dma::DMA_BASE,
|
||||
io::{BG0CNT, DISPCNT, WAITCNT},
|
||||
memory::{OAM_START, PALETTE_START},
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::*;
|
||||
use gba_rust::{bios::INVALID_ARGUMENT_TRAP, dma::DMA_BASE, memory::OAM_START};
|
||||
use gba_core::{bios::INVALID_ARGUMENT_TRAP, dma::DMA_BASE, memory::OAM_START};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Block {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::{BG2CNT, BG2PA, BG2X, BG2Y, DISPCNT, GREENSWAP},
|
||||
memory::{Memory, OAM_START as OAM, PALETTE_START as PAL, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888, Framebuffer, VideoError, WIDTH},
|
||||
|
|
@ -293,13 +293,13 @@ fn bitmap_green_swap_disabled_bg_and_forced_blank_remain_consistent() {
|
|||
|
||||
fn assert_demo_frame(
|
||||
f: &Framebuffer,
|
||||
mode: gba_rust::bitmap_demo::BitmapMode,
|
||||
mode: gba_demos::bitmap_demo::BitmapMode,
|
||||
pan: (i32, i32),
|
||||
rotated: bool,
|
||||
zoomed: bool,
|
||||
page: usize,
|
||||
) {
|
||||
use gba_rust::bitmap_demo::BitmapMode;
|
||||
use gba_demos::bitmap_demo::BitmapMode;
|
||||
let (w, h) = if mode == BitmapMode::Mode4 {
|
||||
(240, 160)
|
||||
} else {
|
||||
|
|
@ -346,10 +346,8 @@ fn assert_demo_frame(
|
|||
|
||||
#[test]
|
||||
fn cpu_demos_copy_both_pages_and_flip_during_vblank_every_32_updates() {
|
||||
use gba_rust::{
|
||||
bitmap_demo::{BitmapDemo, BitmapMode, BITMAP_STATE},
|
||||
input::Buttons,
|
||||
};
|
||||
use gba_core::input::Buttons;
|
||||
use gba_demos::bitmap_demo::{BitmapDemo, BitmapMode, BITMAP_STATE};
|
||||
for mode in [BitmapMode::Mode4, BitmapMode::Mode5] {
|
||||
let mut demo = BitmapDemo::new(mode).unwrap();
|
||||
let mut f = Framebuffer::default();
|
||||
|
|
@ -376,10 +374,8 @@ fn cpu_demos_copy_both_pages_and_flip_during_vblank_every_32_updates() {
|
|||
|
||||
#[test]
|
||||
fn cpu_bitmap_controls_pan_rotate_zoom_force_page_and_reset() {
|
||||
use gba_rust::{
|
||||
bitmap_demo::{BitmapDemo, BitmapMode, BITMAP_STATE},
|
||||
input::{Button, Buttons},
|
||||
};
|
||||
use gba_core::input::{Button, Buttons};
|
||||
use gba_demos::bitmap_demo::{BitmapDemo, BitmapMode, BITMAP_STATE};
|
||||
for mode in [BitmapMode::Mode4, BitmapMode::Mode5] {
|
||||
let mut demo = BitmapDemo::new(mode).unwrap();
|
||||
let mut f = Framebuffer::default();
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::{Cpu, CpuError, InstructionSet},
|
||||
demo_program,
|
||||
memory::{Memory, MemoryError, ROM_START},
|
||||
DEMO_STEPS,
|
||||
};
|
||||
use gba_demos::{demo_program, DEMO_STEPS};
|
||||
|
||||
fn program(words: &[u32]) -> Memory {
|
||||
Memory::new(words.iter().flat_map(|word| word.to_le_bytes()).collect()).unwrap()
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::{Cpu, Mode},
|
||||
display::{CYCLES_PER_FRAME, CYCLES_PER_LINE, HBLANK_START, LINES_PER_FRAME, VBLANK_START},
|
||||
io::{DISPCNT, DISPSTAT, IE, IF, IME, TIMER_BASE, VCOUNT},
|
||||
|
|
@ -397,7 +397,7 @@ fn failed_block_store_does_not_change_window_controls_or_advance_display() {
|
|||
assert!(machine.step().is_err());
|
||||
assert_eq!(machine.cpu(), &before);
|
||||
assert_eq!(machine.memory().display_position(), position);
|
||||
assert_eq!(machine.memory().read32(gba_rust::io::WININ).unwrap(), 0);
|
||||
assert_eq!(machine.memory().read32(gba_core::io::WININ).unwrap(), 0);
|
||||
assert_eq!(machine.memory().read16(DISPSTAT).unwrap(), 0);
|
||||
assert_eq!(machine.memory().read16(IF).unwrap(), 0);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::{Cpu, Mode},
|
||||
display::{CYCLES_PER_FRAME, CYCLES_PER_LINE, HBLANK_START, VBLANK_START},
|
||||
dma::{DmaError, DMA_BASE, DMA_STRIDE},
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::*,
|
||||
memory::{Memory, MemoryError, OAM_START as OAM, PALETTE_START as PAL, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888 as rgb, Framebuffer, HEIGHT, WIDTH},
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
use gba_core::input::{Button, Buttons};
|
||||
use gba_demos::{
|
||||
effects_demo::{EffectsDemo, EFFECTS_STATE},
|
||||
input::{Button, Buttons},
|
||||
tile_demo::TileDemo,
|
||||
};
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ fn cpu_window_demo_retains_active_region_when_bottom_moves_beyond_vcount_range()
|
|||
|
||||
#[test]
|
||||
fn dma_word_write_updates_selection_and_coefficients_together() {
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
dma::DMA_BASE,
|
||||
machine::{Machine, StepKind},
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::{Cpu, InstructionSet, Mode},
|
||||
demo_bios, exception_demo_program,
|
||||
memory::{Memory, MemoryError, BIOS_SIZE, ROM_START},
|
||||
EXCEPTION_DEMO_STEPS,
|
||||
};
|
||||
use gba_demos::{demo_bios, exception_demo_program, EXCEPTION_DEMO_STEPS};
|
||||
|
||||
#[test]
|
||||
fn original_demo_enters_supervisor_and_returns_to_arm_and_thumb() {
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use gba_rust::{
|
||||
graphics_demo::{GraphicsDemo, BACKGROUND, DEMO_STATE, SQUARE_SIZE},
|
||||
use gba_core::{
|
||||
input::{Button, Buttons},
|
||||
io::{BG2PA, BG2PD, DISPCNT, GREENSWAP, KEYINPUT},
|
||||
memory::{Memory, MemoryError, PALETTE_START, VRAM_START},
|
||||
timing::{bus_cycles, AccessKind, AccessWidth},
|
||||
video::{rgb555_to_rgb888, Framebuffer, VideoError, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::graphics_demo::{GraphicsDemo, BACKGROUND, DEMO_STATE, SQUARE_SIZE};
|
||||
|
||||
fn mode3() -> Memory {
|
||||
let mut memory = Memory::new(vec![]).unwrap();
|
||||
|
|
@ -65,7 +65,7 @@ fn cpu_program_draws_mode3_and_moves_from_keyinput_without_host_vram_writes() {
|
|||
assert_eq!(position.frames, previous.frames + 1);
|
||||
assert_eq!(
|
||||
demo.machine().cycles() - previous_cycles,
|
||||
u64::from(gba_rust::display::CYCLES_PER_FRAME) + u64::from(position.line_cycle)
|
||||
u64::from(gba_core::display::CYCLES_PER_FRAME) + u64::from(position.line_cycle)
|
||||
- u64::from(previous.line_cycle)
|
||||
);
|
||||
assert_demo_frame(&demo, &frame, 114, 70, 0x7fff);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::{Cpu, InstructionSet, Mode},
|
||||
display::{CYCLES_PER_FRAME, CYCLES_PER_LINE, HBLANK_START, VBLANK_START},
|
||||
dma::{DmaError, DMA_BASE},
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::{Cpu, CpuError, InstructionSet, Mode},
|
||||
io::{IE, IF, IME, TIMER_BASE, WAITCNT},
|
||||
machine::{Machine, MachineError, StepKind},
|
||||
memory::{Memory, MemoryError, BIOS_SIZE, ROM_START},
|
||||
timer_demo::{timer_demo, TIMER_DEMO_STEPS},
|
||||
};
|
||||
use gba_demos::timer_demo::{timer_demo, TIMER_DEMO_STEPS};
|
||||
|
||||
fn words(values: &[u32]) -> Vec<u8> {
|
||||
values
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::memory::{Memory, MemoryError, ROM_START};
|
||||
use gba_core::memory::{Memory, MemoryError, ROM_START};
|
||||
|
||||
#[test]
|
||||
fn halfword_and_word_writes_are_little_endian() {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::*,
|
||||
memory::{Memory, MemoryError, OAM_START as OAM, PALETTE_START as PAL, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888 as rgb, Framebuffer, HEIGHT, WIDTH},
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use super::*;
|
||||
use gba_rust::{
|
||||
input::{Button, Buttons},
|
||||
use gba_core::input::{Button, Buttons};
|
||||
use gba_demos::{
|
||||
mosaic_demo::{MosaicDemo, MOSAIC_STATE},
|
||||
tile_demo::TileDemo,
|
||||
};
|
||||
|
|
@ -72,7 +72,7 @@ fn both_bypasses_restore_original_scene_with_scroll_rotation_zoom_and_reset() {
|
|||
|
||||
#[test]
|
||||
fn dma_word_write_sets_bg_and_obj_fields_while_unused_halfword_ignores_writes() {
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
dma::DMA_BASE,
|
||||
machine::{Machine, StepKind},
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
display::{
|
||||
CYCLES_PER_FRAME as FRAME, CYCLES_PER_LINE as LINE, HBLANK_START as HB, VBLANK_START as VB,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
display::{CYCLES_PER_FRAME, CYCLES_PER_LINE, HBLANK_START, VBLANK_START},
|
||||
dma::DMA_BASE,
|
||||
|
|
@ -6,9 +6,9 @@ use gba_rust::{
|
|||
io::*,
|
||||
machine::{Machine, StepKind},
|
||||
memory::{Memory, OAM_START as OAM, PALETTE_START as PAL, ROM_START, VRAM_START as VRAM},
|
||||
raster_demo::{RasterDemo, RASTER_STATE, RASTER_TABLE},
|
||||
video::{rgb555_to_rgb888 as rgb, Framebuffer, VideoError, HEIGHT, WIDTH},
|
||||
};
|
||||
use gba_demos::raster_demo::{RasterDemo, RASTER_STATE, RASTER_TABLE};
|
||||
|
||||
#[path = "scanlines/capture.rs"]
|
||||
mod capture;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//! Regression tests for the nominal allowance, not hardware fetch cutoffs.
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
display::{CYCLES_PER_LINE as LINE, VBLANK_START as VB},
|
||||
dma::DMA_BASE,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
display::{CYCLES_PER_FRAME as FRAME, CYCLES_PER_LINE as LINE, VBLANK_START as VB},
|
||||
dma::DMA_BASE,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::{BG0CNT, BG2CNT, DISPCNT, GREENSWAP},
|
||||
memory::{Memory, MemoryError, OAM_START as OAM, PALETTE_START as PAL, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888, Framebuffer, VideoError, WIDTH},
|
||||
|
|
@ -339,7 +339,7 @@ fn green_swap_applies_after_sprite_composition() {
|
|||
|
||||
#[test]
|
||||
fn oam_bus_uses_one_cycle_for_every_width() {
|
||||
use gba_rust::timing::{bus_cycles, AccessKind, AccessWidth};
|
||||
use gba_core::timing::{bus_cycles, AccessKind, AccessWidth};
|
||||
for kind in [AccessKind::Sequential, AccessKind::NonSequential] {
|
||||
for width in [AccessWidth::Byte, AccessWidth::Halfword, AccessWidth::Word] {
|
||||
assert_eq!(bus_cycles(0, OAM, width, kind), 1);
|
||||
|
|
@ -349,7 +349,7 @@ fn oam_bus_uses_one_cycle_for_every_width() {
|
|||
|
||||
#[test]
|
||||
fn dma_copies_words_to_oam_and_reads_them_back() {
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
dma::DMA_BASE,
|
||||
machine::{Machine, StepKind},
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::*,
|
||||
memory::{Memory, MemoryError, PALETTE_START as PAL, VRAM_START as VRAM},
|
||||
video::{rgb555_to_rgb888, Framebuffer, VideoError, WIDTH},
|
||||
|
|
@ -308,10 +308,8 @@ fn assert_scene(
|
|||
|
||||
#[test]
|
||||
fn cpu_tile_demo_copies_assets_scrolls_wraps_cancels_opposites_and_resets() {
|
||||
use gba_rust::{
|
||||
input::{Button, Buttons},
|
||||
tile_demo::{TileDemo, TILE_STATE},
|
||||
};
|
||||
use gba_core::input::{Button, Buttons};
|
||||
use gba_demos::tile_demo::{TileDemo, TILE_STATE};
|
||||
let mut demo = TileDemo::new().unwrap();
|
||||
let mut frame = Framebuffer::default();
|
||||
assert_eq!(demo.machine().memory().read16(VRAM).unwrap(), 0);
|
||||
|
|
@ -367,11 +365,11 @@ fn cpu_tile_demo_copies_assets_scrolls_wraps_cancels_opposites_and_resets() {
|
|||
|
||||
#[test]
|
||||
fn cpu_sprite_controls_flip_and_change_priority_through_oam() {
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
input::{Button, Buttons},
|
||||
memory::OAM_START,
|
||||
tile_demo::TileDemo,
|
||||
};
|
||||
use gba_demos::tile_demo::TileDemo;
|
||||
let mut demo = TileDemo::new().unwrap();
|
||||
let mut frame = Framebuffer::default();
|
||||
for _ in 0..16 {
|
||||
|
|
@ -411,11 +409,11 @@ fn cpu_sprite_controls_flip_and_change_priority_through_oam() {
|
|||
|
||||
#[test]
|
||||
fn cpu_affine_controls_write_matrices_preserve_center_and_return_to_regular_mode() {
|
||||
use gba_rust::{
|
||||
use gba_core::{
|
||||
input::{Button, Buttons},
|
||||
memory::OAM_START,
|
||||
tile_demo::TileDemo,
|
||||
};
|
||||
use gba_demos::tile_demo::TileDemo;
|
||||
let mut demo = TileDemo::new().unwrap();
|
||||
let mut frame = Framebuffer::default();
|
||||
// Put foreground crosses over the sprite so X also tests affine composition.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
io::{IE, IF, IME, TIMER_BASE},
|
||||
memory::{Memory, MemoryError},
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
io::{IE, IF, IME, TIMER_BASE, WAITCNT},
|
||||
machine::{Machine, StepKind},
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use gba_rust::{
|
||||
use gba_core::{
|
||||
cpu::Cpu,
|
||||
display::{
|
||||
CYCLES_PER_FRAME as FRAME, CYCLES_PER_LINE as LINE, HBLANK_START as HB, VBLANK_START as VB,
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue