feat(bios): support sound and serial register reset
This commit is contained in:
parent
cb2772cef8
commit
d6a47a3e12
14 changed files with 278 additions and 47 deletions
|
|
@ -54,6 +54,8 @@ Use `--test-suite suite.json` for [repeatable headless ROM assertions](docs/rom-
|
|||
| [docs/hardware/bios.md](docs/hardware/bios.md) | The original BIOS replacement and each supported service |
|
||||
| [docs/hardware/timers-irq.md](docs/hardware/timers-irq.md) | Timers, interrupt registers, HALT/STOP, and power control |
|
||||
| [docs/hardware/dma.md](docs/hardware/dma.md) | DMA channels, triggers, and timing |
|
||||
| [docs/hardware/audio.md](docs/hardware/audio.md) | Disabled sound initialization and remaining audio work |
|
||||
| [docs/hardware/serial.md](docs/hardware/serial.md) | Disconnected serial initialization and transfer limits |
|
||||
| [docs/hardware/display-timing.md](docs/hardware/display-timing.md) | Display clock, status, IRQs, and scanline capture |
|
||||
| [docs/hardware/video.md](docs/hardware/video.md) | Backgrounds, sprites, mosaic, windows, color effects, and input |
|
||||
| [docs/references.md](docs/references.md) | External hardware references and emulator sources consulted |
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@ pub fn boot(rom: Vec<u8>) -> Result<Machine, MemoryError> {
|
|||
/// and registers other than each arithmetic service's documented outputs.
|
||||
/// SoftReset instead clears BIOS work RAM, resets specified CPU banks, and enters
|
||||
/// ROM or RAM in ARM System mode with IRQ masked. It does not reset devices.
|
||||
/// RegisterRamReset clears selected RAM and supported I/O registers. Serial/sound
|
||||
/// reset flags reach a diagnostic before display or reset writes.
|
||||
/// RegisterRamReset clears selected RAM and supported I/O registers, including
|
||||
/// disabled sound and disconnected serial reset state. Active audio/link operations
|
||||
/// remain diagnostic in the device model.
|
||||
/// IRQ callbacks must preserve r4–r11, acknowledge IF, update IRQ_FLAGS for wait
|
||||
/// services, and return with BX lr. Nested IRQs and SWIs from callbacks are unsupported.
|
||||
/// Service routines use the Supervisor stack; exact firmware stack layout and
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
//! Original ARM SoftReset and selective RegisterRamReset services.
|
||||
//! Serial/sound reset requests are diagnostics until those devices are modeled.
|
||||
//! Sound and serial reset use the disabled/disconnected I/O subset.
|
||||
|
||||
use super::{ArmImage, IRQ_STACK, ROM_START, SVC_STACK, SYSTEM_STACK};
|
||||
use crate::{
|
||||
dma::DMA_BASE,
|
||||
io::{DISPCNT, IE, IME, TIMER_BASE},
|
||||
io::{
|
||||
DISPCNT, IE, IME, JOYCNT, JOY_RECV, JOY_TRANS, RCNT, SIOCNT, SIODATA32, SIODATA8,
|
||||
SOUNDBIAS, SOUNDCNT_H, SOUNDCNT_X, TIMER_BASE, WAVE_RAM,
|
||||
},
|
||||
};
|
||||
|
||||
pub(super) fn emit(a: &mut ArmImage) {
|
||||
|
|
@ -47,14 +50,15 @@ pub(super) fn emit(a: &mut ArmImage) {
|
|||
|
||||
fn emit_ram_reset(a: &mut ArmImage) {
|
||||
a.label("register_ram_reset");
|
||||
// Validate unsupported devices before forced blank or any reset writes.
|
||||
// Higher flag bits are ignored, as in the documented low-byte flag format.
|
||||
a.emit(0xe310_0060); // TST r0,#serial|sound
|
||||
a.branch(1, "invalid_argument");
|
||||
a.literal(1, DISPCNT);
|
||||
a.emit(0xe3a0_2080); // MOV r2,#forced blank (also clear other DISPCNT bits)
|
||||
a.emit(0xe1c1_20b0); // STRH r2,[r1]
|
||||
a.emit(0xe3a0_3000); // MOV r3,#0 (shared fill value)
|
||||
|
||||
// Documented BIOS side effect occurs even when serial reset is not selected.
|
||||
a.literal(1, SIODATA32);
|
||||
store_halfword(a, 0);
|
||||
for (flag, start, bytes, next) in [
|
||||
(1, 0x0200_0000, 0x40000, "ram_reset_iwram"),
|
||||
(2, 0x0300_0000, 0x7e00, "ram_reset_palette"),
|
||||
|
|
@ -67,6 +71,35 @@ fn emit_ram_reset(a: &mut ArmImage) {
|
|||
clear_words(a, start, bytes);
|
||||
a.label(next);
|
||||
}
|
||||
a.emit(0xe310_0020); // TST r0,#serial
|
||||
a.branch(0, "ram_reset_sound");
|
||||
a.literal(1, SIOCNT);
|
||||
store_halfword(a, 0);
|
||||
a.literal(1, SIODATA8);
|
||||
store_halfword(a, 0);
|
||||
a.literal(1, RCNT);
|
||||
a.emit(0xe3a0_3902); // MOV r3,#0x8000 (GPIO, all pins inputs)
|
||||
store_halfword(a, 0);
|
||||
a.emit(0xe3a0_3000); // MOV r3,#0
|
||||
a.literal(1, JOYCNT);
|
||||
store_halfword(a, 0);
|
||||
clear_words(a, JOY_RECV, 4);
|
||||
clear_words(a, JOY_TRANS, 4);
|
||||
|
||||
a.label("ram_reset_sound");
|
||||
a.emit(0xe310_0040); // TST r0,#sound
|
||||
a.branch(0, "ram_reset_other");
|
||||
a.literal(1, SOUNDCNT_X);
|
||||
store_halfword(a, 0); // Disable sound; PSG register state is held in reset.
|
||||
a.literal(1, SOUNDCNT_H);
|
||||
store_halfword(a, 0);
|
||||
a.literal(1, SOUNDBIAS);
|
||||
a.emit(0xe3a0_3c02); // MOV r3,#0x200 (bias default)
|
||||
store_halfword(a, 0);
|
||||
a.emit(0xe3a0_3000); // MOV r3,#0
|
||||
clear_words(a, WAVE_RAM, 16); // Accessible inactive bank; other bank cannot be enabled yet.
|
||||
|
||||
a.label("ram_reset_other");
|
||||
a.emit(0xe310_0080); // TST r0,#other registers
|
||||
a.branch(0, "return");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use super::*;
|
||||
use gba_core::{
|
||||
bios::INVALID_ARGUMENT_TRAP,
|
||||
dma::{DmaError, DMA_BASE, DMA_STRIDE},
|
||||
input::Buttons,
|
||||
io::{
|
||||
|
|
@ -185,34 +184,57 @@ fn internal_ram_clear_preserves_bios_work_area_except_common_swi_frame() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn all_serial_sound_requests_fail_before_forced_blank_or_memory_clear() {
|
||||
fn serial_sound_reset_flags_are_selective_and_all_devices_return() {
|
||||
use gba_core::io::{
|
||||
RCNT, SIOCNT, SIODATA32, SIODATA8, SOUNDBIAS, SOUNDCNT_H, SOUNDCNT_X, WAVE_RAM,
|
||||
};
|
||||
for thumb in [false, true] {
|
||||
for flags in (0..256).filter(|flags| flags & 0x60 != 0) {
|
||||
let (mut m, _) = prepare(flags, thumb, 0x1f);
|
||||
for flags in [
|
||||
0, 0x20, 0x40, 0x60, 0x80, 0xff, 0xffffff20, 0xffffff40, 0xffffffff,
|
||||
] {
|
||||
let (mut m, pc) = prepare(flags, thumb, 0x1f);
|
||||
seed_samples(&mut m);
|
||||
m.memory_mut().write16(DISPCNT, 0x0403).unwrap();
|
||||
for _ in 0..1000 {
|
||||
let before = m.cpu().clone();
|
||||
let cycles = m.cycles();
|
||||
let timing = m.last_timing();
|
||||
if let Err(error) = m.step() {
|
||||
assert!(matches!(
|
||||
error,
|
||||
MachineError::Cpu(CpuError::UnsupportedInstruction {
|
||||
instruction: INVALID_ARGUMENT_TRAP,
|
||||
..
|
||||
})
|
||||
));
|
||||
assert_eq!(m.cpu(), &before);
|
||||
assert_eq!(m.cycles(), cycles);
|
||||
assert_eq!(m.last_timing(), timing);
|
||||
assert_eq!(m.step(), Err(error));
|
||||
break;
|
||||
}
|
||||
let bus = m.memory_mut();
|
||||
bus.write32(SIODATA32, MARKER).unwrap();
|
||||
bus.write16(SIODATA8, 0x55).unwrap();
|
||||
bus.write16(SIOCNT, 0x500b).unwrap();
|
||||
bus.write16(RCNT, 0x80fa).unwrap();
|
||||
bus.write16(SOUNDCNT_H, 0xffff).unwrap();
|
||||
bus.write16(SOUNDBIAS, 0xffff).unwrap();
|
||||
for offset in 0..16 {
|
||||
bus.write8(WAVE_RAM + offset, 0x5a).unwrap();
|
||||
}
|
||||
complete(&mut m, pc);
|
||||
check_samples(&m, flags);
|
||||
let bus = m.memory();
|
||||
assert_eq!(bus.read32(SIODATA32).unwrap(), MARKER & 0xffff0000); // Unconditional low-halfword clear.
|
||||
assert_eq!(
|
||||
bus.read16(SIODATA8).unwrap(),
|
||||
if flags & 0x20 != 0 { 0 } else { 0x55 }
|
||||
);
|
||||
assert_eq!(
|
||||
bus.read16(SIOCNT).unwrap(),
|
||||
if flags & 0x20 != 0 { 4 } else { 0x500b }
|
||||
);
|
||||
assert_eq!(
|
||||
bus.read16(RCNT).unwrap(),
|
||||
if flags & 0x20 != 0 { 0x800f } else { 0x80fa }
|
||||
);
|
||||
assert_eq!(
|
||||
bus.read16(SOUNDCNT_H).unwrap(),
|
||||
if flags & 0x40 != 0 { 0 } else { 0x770f }
|
||||
);
|
||||
assert_eq!(
|
||||
bus.read16(SOUNDBIAS).unwrap(),
|
||||
if flags & 0x40 != 0 { 0x200 } else { 0xc3fe }
|
||||
);
|
||||
assert_eq!(bus.read16(SOUNDCNT_X).unwrap(), 0);
|
||||
for offset in 0..16 {
|
||||
assert_eq!(
|
||||
bus.read8(WAVE_RAM + offset).unwrap(),
|
||||
if flags & 0x40 != 0 { 0 } else { 0x5a }
|
||||
);
|
||||
}
|
||||
assert!(m.step().is_err());
|
||||
assert_eq!(m.memory().read16(DISPCNT).unwrap(), 0x0403);
|
||||
check_samples(&m, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ The repository is a Cargo workspace with three crates:
|
|||
| `crates/gba-core/src/cpu/fetch_history_tests.rs` | Shared sample consumption, no execution-entry rereads, and failed-step retry |
|
||||
| `crates/gba-core/src/cpu/fetch_boundary_tests.rs` | Actual fetch-region snapshots, split refills, IWRAM lane requirements, ROM-window boundaries, and nominal timing |
|
||||
| `crates/gba-core/src/io.rs` | I/O registers, timers, HALT/STOP wake-up, next-event bounds, and IRQ latches |
|
||||
| `crates/gba-core/src/io/inactive.rs` | Disabled sound and disconnected serial initialization with explicit unsupported-activity validation |
|
||||
| `crates/gba-core/tests/inactive_devices.rs` | Device masks, wave RAM, GPIO pull-ups, serial data, and failed CPU/DMA write isolation |
|
||||
| `crates/gba-core/src/io/timer_step.rs` | Staged timer bank, shared divider phase, and timer IF bits at ordered CPU/DMA bus phases |
|
||||
| `crates/gba-core/src/memory/timer_step_tests.rs` | Timer access phases, coherent lanes, cascades, IF ordering, rollback, DMA, idle, and clock ownership |
|
||||
| `crates/gba-core/src/display.rs` | Display clock, scanline status, comparison edges, and display IRQ events |
|
||||
|
|
|
|||
49
docs/hardware/audio.md
Normal file
49
docs/hardware/audio.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Sound initialization subset
|
||||
|
||||
Sound synthesis and host audio output are not implemented.
|
||||
The core now models disabled sound-register state so firmware can perform a functional sound reset.
|
||||
This is not a silent-audio compatibility mode. Enabling sound returns an explicit diagnostic.
|
||||
|
||||
## Supported state
|
||||
|
||||
| Address | Behavior |
|
||||
| --- | --- |
|
||||
| `0x04000060..0x04000081` | Programmable sound generator (PSG) registers remain zero; writes have no effect while master sound is disabled |
|
||||
| `0x04000082` (`SOUNDCNT_H`) | Retains mixing/routing/timer configuration with readback mask `0x770f` |
|
||||
| `0x04000084` (`SOUNDCNT_X`) | Reads zero; status flags are read-only; a write setting bit 7 fails |
|
||||
| `0x04000088` (`SOUNDBIAS`) | Retains bias/resolution configuration with mask `0xc3fe`; no analog output is generated |
|
||||
| `0x04000090..0x0400009f` | Read/write wave RAM in the CPU-accessible inactive bank |
|
||||
|
||||
Unused mapped bytes through `0x0400008b` read zero and ignore writes.
|
||||
The FIFO reset strobes in `SOUNDCNT_H` do not latch. No FIFO data can be queued in this subset.
|
||||
FIFO addresses and the remaining sound-region holes stay unmapped.
|
||||
All sound configuration starts at zero in raw memory. RegisterRamReset bit 6 sets the functional bias default to `0x0200`.
|
||||
|
||||
With master sound disabled, `SOUND3CNT_L` stays zero. The CPU accesses wave bank 1.
|
||||
Bank 0 cannot be selected or played and remains zero. Disabling master sound does not erase wave RAM.
|
||||
The BIOS reset explicitly clears the accessible wave RAM through ordinary stores.
|
||||
Future bank switching and channel playback need a complete sound engine, not a larger register array.
|
||||
|
||||
## Diagnostics and atomicity
|
||||
|
||||
A write setting `SOUNDCNT_X` bit 7 returns `MemoryError::UnsupportedIo`, including the address, byte value, and operation.
|
||||
Status bits and unused bits alone do not enable sound.
|
||||
Validation occurs before any bytes in the access are written.
|
||||
Block stores validate every register value before committing earlier writes. Failed CPU and DMA steps remain retryable.
|
||||
|
||||
Original tests cover disabled-register writes, masks, byte lanes, wave retention, and BIOS reset selection.
|
||||
They also check rejected sound activation through byte/word accesses, ARM block stores, and DMA without partial state changes.
|
||||
|
||||
## Remaining work
|
||||
|
||||
Implement channel clocks, length/envelope/sweep state, wave banking, FIFO consumption, timer-triggered sound DMA, and mixing.
|
||||
Add a host-independent sample interface before connecting a desktop audio backend.
|
||||
Do not acknowledge active sound requests without implementing their device behavior.
|
||||
|
||||
## References
|
||||
|
||||
- [GBATEK sound control registers](https://problemkaputt.de/gbatek-gba-sound-control-registers.htm): disabled PSG behavior, master enable, masks, FIFO reset strobes, and bias.
|
||||
- [GBATEK](https://mgba-emu.github.io/gbatek/): channel 3 wave-bank access and register layout.
|
||||
- [mGBA BIOS service implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/bios.c): functional reset defaults. No upstream implementation was copied.
|
||||
|
||||
Reset values are source-backed. Exact Nintendo firmware ordering, timing, and analog behavior are not established.
|
||||
|
|
@ -40,7 +40,7 @@ Supported software interrupt services:
|
|||
| Number | Service | Behavior |
|
||||
| --- | --- | --- |
|
||||
| `0x00` | SoftReset | Clear BIOS work RAM and reset CPU registers/stacks; restart in ROM or RAM without returning |
|
||||
| `0x01` | RegisterRamReset | r0 selects RAM and supported I/O resets; force blank; reject serial/sound flags |
|
||||
| `0x01` | RegisterRamReset | r0 selects RAM and supported I/O resets, including disabled sound and disconnected serial state |
|
||||
| `0x02` | Halt | Wait for `IE & IF`; preserve IME and caller registers |
|
||||
| `0x03` | Stop | Freeze system clocks until an enabled live keypad condition wakes the system; preserve caller state |
|
||||
| `0x04` | IntrWait | `r0`: discard old selected flags when nonzero; `r1`: flags to wait for |
|
||||
|
|
@ -215,21 +215,26 @@ Supported flags can be combined:
|
|||
| 2 | Clear palette RAM: `0x05000000..0x050003ff` |
|
||||
| 3 | Clear all 96 KiB of video RAM: `0x06000000..0x06017fff` |
|
||||
| 4 | Clear sprite attribute memory (OAM): `0x07000000..0x070003ff` |
|
||||
| 5 | Serial reset: unsupported |
|
||||
| 6 | Sound reset: unsupported |
|
||||
| 5 | Reset supported idle serial state and select general-purpose inputs |
|
||||
| 6 | Reset disabled sound state, mixing control, bias, and accessible wave RAM |
|
||||
| 7 | Reset supported display, DMA, timer, and interrupt registers as described below |
|
||||
|
||||
**Unsupported flags:** any request containing bit 5 or 6 reaches `bios::INVALID_ARGUMENT_TRAP`.
|
||||
Validation occurs before forced blank or RAM/I/O reset writes, but after the common SWI stack save.
|
||||
This includes the common all-devices request `r0=0xff`; it is not silently treated as a successful full reset.
|
||||
Serial and audio devices remain unimplemented. The firmware's unconditional serial-data side effect is not reproduced.
|
||||
All low-byte flag combinations, including `r0=0xff`, are accepted within the supported device subset.
|
||||
This is not full audio or serial support. [Sound activation](audio.md) and [serial transfers](serial.md) still fail explicitly.
|
||||
The firmware always clears the low halfword of SIODATA32, even when bit 5 is clear; its upper halfword is preserved.
|
||||
|
||||
Every supported request first writes `DISPCNT=0x0080`, including requests with no selected flags.
|
||||
This forces a white screen and clears other display-control bits.
|
||||
RAM clears then run in bit order, using ordinary word stores.
|
||||
Zeroed OAM contains regular sprites at the origin, not disabled sprites; software must configure them before enabling objects.
|
||||
|
||||
Bit 7 runs after the selected RAM clears:
|
||||
After the RAM clears, bit 5 clears SIOCNT and SIODATA8, writes RCNT=0x8000, and clears supported Joybus reset registers.
|
||||
Disconnected general-purpose inputs read high, so RCNT reads back as 0x800f.
|
||||
Bit 6 writes SOUNDCNT_X=0, SOUNDCNT_H=0, and SOUNDBIAS=0x0200, then clears the accessible wave RAM bank.
|
||||
Disabled PSG registers remain zero. The other wave bank cannot be enabled in the current subset and remains zero.
|
||||
Reset does not produce audio, fabricate serial transfers, or bypass normal bus accesses.
|
||||
|
||||
Bit 7 runs after the selected RAM and sound/serial resets:
|
||||
|
||||
- Disable IME.
|
||||
- Disable all four DMA channels, then zero their source, destination, count, and control registers.
|
||||
|
|
@ -244,7 +249,7 @@ Read-only display status and VCOUNT continue to reflect the advancing display cl
|
|||
GREENSWAP, KEYINPUT/button state, KEYCNT, POSTFLG, and BIOS IRQ communication words are not reset.
|
||||
Bit 7 covers only the listed registers. A later matching input sample can request keypad IRQ again after IF acknowledgement.
|
||||
|
||||
Without bit 7, device configuration remains unchanged except for DISPCNT.
|
||||
Without their corresponding reset flags, device configuration remains unchanged except for DISPCNT and the SIODATA32 low halfword.
|
||||
IRQ delivery stays CPU-masked during the call. The service restores the caller's mask on return.
|
||||
Timers and DMA continue until their reset writes, if selected; this service does not stop clocks or replace frame-capture history.
|
||||
Pending IRQs remain pending without bit 7 and can be delivered after return.
|
||||
|
|
@ -504,5 +509,5 @@ Unsupported SWIs, unsupported exception vectors, and null/misaligned IRQ callbac
|
|||
The CPU reports `CpuError::UnsupportedInstruction` with `bios::UNSUPPORTED_TRAP`, rather than silently treating a service as a no-op.
|
||||
Invalid arithmetic/decompression arguments use the same CPU error type with the distinct `bios::INVALID_ARGUMENT_TRAP` instruction.
|
||||
Prior boot/service steps remain committed on failure.
|
||||
RegisterRamReset serial/sound flags, HardReset, and serial/Game Pak STOP wake-up remain unimplemented.
|
||||
Active sound, serial transfers, HardReset, and serial/Game Pak STOP wake-up remain unimplemented.
|
||||
This subset is not sufficient for Pokémon Emerald compatibility.
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ Cartridge writes, save devices, and cartridge peripherals remain unsupported.
|
|||
Both modes call `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.
|
||||
Unsupported services remain diagnostics. RegisterRamReset now accepts sound/serial reset flags, including `r0=0xff`, within the initialization subset.
|
||||
Active sound and serial transfers still fail with device-specific diagnostics; accepting reset does not establish game compatibility.
|
||||
|
||||
## Terminal execution limits and results
|
||||
|
||||
|
|
|
|||
43
docs/hardware/serial.md
Normal file
43
docs/hardware/serial.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Disconnected serial initialization subset
|
||||
|
||||
The core supports idle normal-mode data registers and disconnected general-purpose pins.
|
||||
It does not support link transfers, multiplayer, UART, Joybus communication, or external serial interrupts.
|
||||
Unsupported activity remains diagnostic rather than reporting a fabricated completion.
|
||||
|
||||
## Registers
|
||||
|
||||
- `SIODATA32` at `0x04000120` is a four-byte latch in the supported normal-mode subset.
|
||||
- `SIODATA8` at `0x0400012a` retains its low byte; its upper byte reads zero.
|
||||
- `SIOCNT` at `0x04000128` retains normal 8/32-bit mode, IRQ configuration, clock selection, and the output-data bit.
|
||||
The retained mask is `0x500b`. The disconnected serial input is high, except when a general-purpose output drives it low.
|
||||
Transfer-start bit 7 and multiplayer/UART mode bit 13 return explicit errors.
|
||||
- `RCNT` at `0x04000134` retains general-purpose mode, output latches, and pin directions with mask `0x80ff`.
|
||||
In general-purpose mode, each input reads high through its pull-up. Each output reads its output latch.
|
||||
`RCNT=0x8000` therefore reads back as `0x800f`, not `0x8000`.
|
||||
Joybus mode and GPIO interrupt enable return errors. Normal-mode low-byte pin readback remains unmapped rather than guessed.
|
||||
- `JOYCNT` permits clearing already-empty status flags. Joybus interrupt enable is unsupported.
|
||||
- `JOY_RECV` and `JOY_TRANS` permit only zero writes and zero readback for reset initialization.
|
||||
Nonzero writes return an explicit error. Joybus status and data-transfer side effects are not implemented.
|
||||
|
||||
GPIO means general-purpose input/output. UART means universal asynchronous receiver/transmitter.
|
||||
No external serial device is connected. Elapsed cycles alone do not change serial data or generate an IRQ.
|
||||
Configuration that hardware accepts in other modes can still be rejected by this intentionally limited subset.
|
||||
|
||||
## BIOS reset
|
||||
|
||||
RegisterRamReset always clears the low halfword of SIODATA32, even without bit 5.
|
||||
The upper halfword remains unchanged in this functional subset.
|
||||
With bit 5 selected, the firmware clears SIOCNT and SIODATA8, selects general-purpose inputs, and clears the supported Joybus reset registers.
|
||||
It uses ordinary ARM bus stores, not a host-side reset bypass.
|
||||
|
||||
Original tests cover independent byte lanes, input pull-ups, output directions, reset flag selection, and explicit unsupported operations.
|
||||
Whole-access and block-store validation prevent a rejected control value from committing preceding bytes or registers.
|
||||
|
||||
## References
|
||||
|
||||
- [GBATEK reset functions](https://problemkaputt.de/gbatek-bios-reset-functions.htm): reset flags, general-purpose selection, and the unconditional SIODATA32 side effect.
|
||||
- [GBATEK normal serial mode](https://problemkaputt.de/gbatek-sio-normal-mode.htm): data widths, input status, and control bits.
|
||||
- [GBATEK](https://mgba-emu.github.io/gbatek/): general-purpose pin directions and internal pull-ups.
|
||||
- [mGBA BIOS implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/bios.c): functional serial reset defaults, not copied source.
|
||||
|
||||
Exact firmware write ordering and hardware pin timing remain unverified.
|
||||
|
|
@ -239,6 +239,13 @@ General gameplay and boot graphics:
|
|||
- [tolik518/GBA_Pong](https://github.com/tolik518/GBA_Pong/tree/422e22a5d1f7d11710e03ffc19d5bff6ac95240f): a future homebrew candidate found during research. It has not been built or tested here.
|
||||
- [Paperdomo101/2048-GBA at ae36800d](https://github.com/Paperdomo101/2048-GBA/tree/ae36800dfa1314f96c4c8785b5c2d077fb731aff): reviewed its CC0 license, README, `main.c`, `global.h`, and `storage.c` for SRAM byte accesses and Maxmod initialization. This is a source-level requirement, not a runtime result. The [linked release page](https://basil-termini.itch.io/2048-advance) returned HTTP 522 during download research.
|
||||
|
||||
Disabled sound and disconnected serial reset:
|
||||
|
||||
- [GBATEK BIOS reset functions](https://problemkaputt.de/gbatek-bios-reset-functions.htm), for flag selection and unconditional SIODATA32 low-halfword destruction.
|
||||
- [GBATEK sound control](https://problemkaputt.de/gbatek-gba-sound-control-registers.htm), for disabled PSG state, master enable, mixing masks, and bias.
|
||||
- [GBATEK normal serial mode](https://problemkaputt.de/gbatek-sio-normal-mode.htm) and its [general-purpose register chapter](https://mgba-emu.github.io/gbatek/), for data widths, control fields, and disconnected input pull-ups.
|
||||
- [mGBA BIOS implementation at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/bios.c), for functional serial and sound reset defaults. Exact firmware ordering and timing remain unverified.
|
||||
|
||||
Use [GBATEK](https://problemkaputt.de/gbatek.htm) and ARM7TDMI documentation for further hardware work.
|
||||
Only use game ROMs that you may lawfully use. Do not commit game ROMs, BIOS files, or game assets.
|
||||
The ignore file excludes `roms/`, common game ROM extensions, and save files.
|
||||
|
|
|
|||
54
docs/research/emerald-reset.md
Normal file
54
docs/research/emerald-reset.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Local Emerald startup: device reset
|
||||
|
||||
## Initial failure
|
||||
|
||||
A user-supplied local Emerald ROM stopped in the original BIOS replacement during `RegisterRamReset(0xff)`.
|
||||
The BIOS deliberately rejected serial/sound flags and executed `INVALID_ARGUMENT_TRAP` (`0xe7f000f1`).
|
||||
This was an unsupported service argument, not an ARM instruction-decoder failure.
|
||||
No ROM bytes, extracted code, or assets were added to the repository.
|
||||
|
||||
## General correction
|
||||
|
||||
The core now provides a bounded [disabled sound](../hardware/audio.md) and [disconnected serial](../hardware/serial.md) initialization model.
|
||||
The BIOS performs reset through original ARM stores against that model.
|
||||
Bit 5 selects general-purpose input pins and clears supported serial reset registers.
|
||||
Bit 6 disables sound, clears mixing configuration and accessible wave RAM, and sets the functional bias default.
|
||||
The low halfword of SIODATA32 is cleared unconditionally, matching the documented BIOS side effect.
|
||||
|
||||
This is not a game-specific bypass. Original ARM and Thumb callers exercise selected flags and the all-device request.
|
||||
Tests verify caller preservation, RAM selection, unselected device state, readback masks, and rejected device activity.
|
||||
Byte, halfword, word, block-store, and DMA validation retain explicit errors without partial register writes.
|
||||
|
||||
## Reproduction and current result
|
||||
|
||||
Use a local ROM that you may lawfully use:
|
||||
|
||||
```sh
|
||||
direnv exec . cargo run --locked --release -- --rom roms/pokemon-emerald.gba --steps 1000000
|
||||
direnv exec . cargo run --locked --release -- --rom roms/pokemon-emerald.gba --window --frames 120
|
||||
```
|
||||
|
||||
Both runs now pass the BIOS reset and stop at the game's sound activation write:
|
||||
|
||||
```text
|
||||
PC=0x082e0518
|
||||
unsupported sound master enable (audio engine not implemented): write 0x8f at 0x04000084
|
||||
```
|
||||
|
||||
The native run captures startup frames before this diagnostic. These are not evidence of a working title screen or gameplay.
|
||||
The window run does not reach its requested frame limit and correctly exits with failure.
|
||||
Terminal execution is also diagnostic, not a compatibility pass.
|
||||
Results apply to this local file; no cartridge revision or checksum was inferred from its filename.
|
||||
|
||||
## Validation and next requirement
|
||||
|
||||
Workspace debug/release tests, strict Clippy, public ARM/Thumb/memory/BIOS checkpoints, and pinned Pong scenarios pass.
|
||||
Native ROM-window tests and graphics smoke modes pass on Darwin arm64.
|
||||
The pinned Pong debug/release reports match.
|
||||
|
||||
The next observed startup requirement is active audio-device behavior, starting at SOUNDCNT_X master enable.
|
||||
Implement channel/FIFO clocks, state, DMA requests, and an output interface before claiming sound support.
|
||||
Do not make enable succeed solely to suppress this diagnostic.
|
||||
Cartridge saves remain a separate required feature. SRAM alone will not support Emerald's Flash save protocol.
|
||||
|
||||
Hardware and emulator references are recorded in the linked subsystem documents.
|
||||
|
|
@ -77,6 +77,8 @@ Update this file when a feature lands or a limit is removed.
|
|||
- Read-only cartridge bytes in the three GBA cartridge windows.
|
||||
- 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=0xff` request.
|
||||
- Sound activation and unsupported serial operations produce explicit address/value diagnostics 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.
|
||||
- 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.
|
||||
|
|
@ -132,7 +134,9 @@ Internal affine origins, vertical window flags, and vertical mosaic counters tra
|
|||
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.
|
||||
There is no sound or cartridge save support.
|
||||
There is no sound synthesis, host audio output, or cartridge save support.
|
||||
The [sound initialization subset](hardware/audio.md) supports disabled register state and wave RAM; master sound enable remains diagnostic.
|
||||
The [serial initialization subset](hardware/serial.md) supports idle normal data and disconnected general-purpose pins, not active transfers.
|
||||
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.
|
||||
|
|
@ -141,6 +145,8 @@ All named graphics demos connect desktop input and rendering to the emulated CPU
|
|||
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, saves, and external BIOS loading remain unavailable. ROM loading does not establish commercial-game compatibility.
|
||||
A local Emerald run now completes its all-device reset and reaches sound activation at `0x04000084`, where it stops explicitly.
|
||||
Its captured startup frames do not establish title-screen or gameplay compatibility. See [the startup result](research/emerald-reset.md).
|
||||
See [cartridge loading](hardware/cartridge.md) for file limits, step budgets, and exit status.
|
||||
The [ROM suite runner](rom-tests.md) has original regressions and a [pinned public ARM baseline](public-arm-tests.md).
|
||||
The pinned public ARM ROM passes its result checkpoint in debug and release builds.
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ direnv exec . python3 -B -m unittest discover -s tools -p 'test_*.py' -v
|
|||
They verify suite selection, pinned URLs, hashes, sizes, checkpoint validation, offline copies, destination safety, and non-overwriting output.
|
||||
The [Pong adapter](public-pong.md) has additional offline tests for its pinned downloads, retained license, and bounded gameplay scenarios.
|
||||
Run the external Pong suite separately; ordinary Cargo and Python tests require no public ROM or network access.
|
||||
Device initialization regressions use original instructions to check disabled sound, wave RAM, disconnected serial pins, and reset flags.
|
||||
They verify explicit activation errors and atomic byte/word/block-store/DMA failure behavior.
|
||||
The optional [local Emerald startup check](research/emerald-reset.md) now reaches sound activation but still fails deliberately there.
|
||||
Thumb cases also verify the return-to-ARM bridge. Command-line tests cover default ARM selection, explicit Thumb/memory/BIOS selection, and errors.
|
||||
Compare/status CPU regressions verify saved flags/masks, bank switching, sequential PC/timing, User/System fallback, and atomic diagnostics.
|
||||
Load-alias regressions cover widths, signed/unaligned values, immediate/register offsets, pre/post-indexing, every non-PC register bank, and address wrapping.
|
||||
|
|
@ -204,7 +207,8 @@ Tile tests cover both color depths, palette banks, flips, all map sizes, scrolli
|
|||
They check errors for unsupported features and out-of-range fetches without changing the output image.
|
||||
The CPU tile demo test verifies asset copies, every pixel, wrapping, opposite directions, reset, and VBlank synchronization.
|
||||
RegisterRamReset tests check full memory regions and all memory-flag combinations from ARM and Thumb.
|
||||
They verify forced blank, reserved flag bits, caller preservation, protected BIOS RAM, and serial/sound diagnostics.
|
||||
They verify forced blank, reserved flag bits, caller preservation, protected BIOS RAM, and selective serial/sound initialization.
|
||||
All-device reset returns from ARM and Thumb; active sound and serial operations remain separately tested diagnostics.
|
||||
Rendering tests check write-only display state, both identity matrices, and the effect of zeroed sprite attributes.
|
||||
Device tests check DMA address/count latches, stopped timer counters, cleared reloads, and IRQ acknowledgement.
|
||||
Other checks cover partial clears, preserved input/device state, and callers whose own RAM code is erased.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ The [pinned Pong homebrew](public-pong.md) passes scripted menus, ball movement,
|
|||
The native Darwin window also starts and presents frames without a diagnostic.
|
||||
This exposed and corrected missing firmware affine-scale initialization, without a game-specific patch.
|
||||
Frame-based scenarios and the preparation adapter now make the result repeatable.
|
||||
The next selected requirement is cartridge SRAM, followed by safe host save persistence.
|
||||
A local Emerald run now passes its initial all-device reset and stops at sound master enable.
|
||||
See [the runtime result](research/emerald-reset.md). Active audio-device behavior is the next demonstrated startup requirement.
|
||||
The separate save requirement remains cartridge SRAM, followed by safe host save persistence.
|
||||
SRAM is byte-addressable battery-backed save memory. Flash and EEPROM remain separate protocols.
|
||||
|
||||
[Paperdomo101/2048-GBA at ae36800d](https://github.com/Paperdomo101/2048-GBA/tree/ae36800dfa1314f96c4c8785b5c2d077fb731aff) is the next independent candidate.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue