feat(cartridge): add explicit Flash identification and banked reads
This commit is contained in:
parent
fce222eea2
commit
8b3b7ae62d
23 changed files with 1042 additions and 52 deletions
|
|
@ -9,7 +9,8 @@ Unsupported operations and invalid calendar payloads return diagnostics.
|
|||
## Selection
|
||||
|
||||
`Memory::set_cartridge_hardware(CartridgeHardware::Rtc)` attaches the bounded interface with initial state.
|
||||
`CartridgeHardware::None` is the default. Selecting either option replaces peripheral state, without changing ROM bytes.
|
||||
`CartridgeHardware::None` is the default. Selecting either option replaces GPIO/RTC state, without changing ROM bytes.
|
||||
The separately selected [Flash device](saves.md) and its array remain unchanged.
|
||||
Call this API between machine steps. The core does not inspect filenames, game headers, or library signatures to select hardware.
|
||||
|
||||
The desktop enables this interface with `--rtc`, in either ROM execution mode:
|
||||
|
|
|
|||
|
|
@ -33,14 +33,18 @@ It does not decode archives or ELF executables. Supply a raw binary with an ARM
|
|||
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.
|
||||
Ordinary cartridge bytes remain read-only. Save devices remain unsupported.
|
||||
Ordinary cartridge bytes remain read-only.
|
||||
Optional `--save-type flash64` or `--save-type flash128` enables [Flash identification and array reads](saves.md).
|
||||
The desktop starts an erased device and does not load or write save files. Programming and erase remain diagnostic.
|
||||
Optional `--rtc` selection enables the bounded [Game Pak GPIO and RTC calendar interface](cartridge-gpio.md).
|
||||
It supports date/time reads, complete writes, reset, and explicit elapsed-time updates. RTC interrupts and persistence remain unsupported.
|
||||
The desktop seeds UTC once, then supplies monotonic host elapsed seconds independently of GBA cycles and STOP.
|
||||
|
||||
Both modes call `bios::boot` with the loaded bytes.
|
||||
With `--rtc`, the host then selects the cartridge peripheral before the first machine step.
|
||||
Without that option, no cartridge peripheral is attached. Duplicate `--rtc` options are rejected.
|
||||
Without that option, no RTC is attached. Duplicate `--rtc` options are rejected.
|
||||
Save-device selection is independent of RTC selection. Omitting `--save-type` leaves save memory unmapped.
|
||||
Unknown save types and duplicate options fail before file access. No ROM-based hardware detection is used.
|
||||
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. RegisterRamReset now accepts sound/serial reset flags, including `r0=0xff`, within the initialization subset.
|
||||
|
|
|
|||
|
|
@ -351,6 +351,8 @@ Palette and video RAM cost 1 cycle for byte/halfword accesses and 2 for words, w
|
|||
ROM costs include one cycle plus the configured wait states for each 16-bit transfer.
|
||||
A ROM word uses two halfword accesses; its second halfword always uses sequential timing.
|
||||
Accesses at 128 KiB ROM boundaries force non-sequential timing for the first halfword.
|
||||
Supported save-byte accesses use WAITCNT bits 0–1: one cycle plus 4, 3, 2, or 8 wait states.
|
||||
Sequential and non-sequential save requests use the same nominal cost. Flash data accesses cancel the opcode prefetch queue.
|
||||
|
||||
`WAITCNT` resets to zero and supports byte, halfword, and word access.
|
||||
The writable mask is `0x5fff`; the Game Pak type flag reads as GBA, and the upper halfword reads as zero.
|
||||
|
|
@ -421,6 +423,7 @@ Important timing limits:
|
|||
- Refill cost calculation does not read target bytes. ARM/Thumb instruction-buffer and local IWRAM bus-history samples add no extra cycles.
|
||||
- Target-pair sampling cannot fail the branch early. An invalid branch target still fails on the following instruction fetch.
|
||||
- Game Pak prefetch is nominal. Full-buffer restart, page boundaries, cancellation, and live WAITCNT changes need independent hardware validation.
|
||||
- PHI and SRAM wait fields are stored; PHI output and SRAM mapping are not implemented.
|
||||
- Save wait fields drive the supported Flash byte-access costs. PHI output and SRAM mapping remain unimplemented.
|
||||
See [Flash access restrictions](saves.md#bus-behavior); wider save transfers and physical bus timing remain unsupported or unverified.
|
||||
- External work RAM timing is fixed. The undocumented memory-control register is not implemented.
|
||||
- Exact DMA startup/resumption delays, display-bus contention, and timer startup/register-write delays remain unmodeled.
|
||||
|
|
|
|||
122
docs/hardware/saves.md
Normal file
122
docs/hardware/saves.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Cartridge Flash identification and read subset
|
||||
|
||||
The core supports explicit Macronix Flash selection, chip identification, array reads, and 128 KiB bank selection.
|
||||
Programming, erase, busy polling, and host save-file persistence remain unimplemented.
|
||||
This is not working game-save support. Unsupported writes fail instead of reporting a completed save.
|
||||
SRAM, EEPROM, and other manufacturers' protocols remain separate work.
|
||||
|
||||
## Selection and initial data
|
||||
|
||||
The desktop accepts either `--save-type flash64` or `--save-type flash128` in ROM terminal/window modes.
|
||||
The option is independent of `--rtc`. Omitting it leaves save memory unmapped.
|
||||
Unknown values and duplicate options fail before opening the ROM.
|
||||
|
||||
```sh
|
||||
direnv exec . cargo run --locked --release -- --rom roms/pokemon-emerald.gba --rtc --save-type flash128 --steps 3000000
|
||||
direnv exec . cargo run --locked --release -- --rom roms/pokemon-emerald.gba --rtc --save-type flash128 --window --frames 60
|
||||
```
|
||||
|
||||
Selection is explicit, not inferred from a filename, ROM signature, or the first write.
|
||||
A 64 KiB device cannot silently become a 128 KiB device.
|
||||
The desktop starts each selected device with erased `0xff` bytes and reports the read-only subset's limits.
|
||||
It does not look for, read, create, or overwrite a save file. Existing game saves remain untouched.
|
||||
The ROM suite schema still uses no save device by default and has no save-selection field yet.
|
||||
|
||||
Core APIs on `Memory`:
|
||||
|
||||
- `set_save_device(SaveDevice)` replaces save hardware and initializes its array to erased bytes.
|
||||
`None`, `Flash64`, and `Flash128` are available. The call preserves GPIO/RTC state.
|
||||
- `load_save_image(&[u8])` supplies an exact-capacity image and resets command state, ID mode, and bank selection.
|
||||
A wrong length or missing device changes nothing. This is host setup, not an emulated program operation.
|
||||
- `save_image()` inspects the complete array, independently of ID mode or selected bank.
|
||||
It returns `None` when no save device is selected.
|
||||
|
||||
Configuration and image replacement occur between machine steps. No filesystem operations belong to the core.
|
||||
Selecting GPIO/RTC hardware does not replace an attached save device or its bytes.
|
||||
This feature can inspect caller-supplied images but cannot modify their data through Flash commands.
|
||||
|
||||
## Bus behavior
|
||||
|
||||
Only `0x0e000000` through `0x0e00ffff` are mapped when a device is selected.
|
||||
The Flash interface uses byte accesses. Halfword/word transfers, DMA, and instruction fetches remain diagnostic.
|
||||
Unverified aliases outside this window remain unmapped rather than returning mirrored data.
|
||||
Ordinary ROM writes remain read-only.
|
||||
|
||||
CPU Flash reads must execute from external or internal work RAM, as required by GBATEK's access description.
|
||||
A read from ROM/BIOS code reports a diagnostic rather than inventing a value for an unsupported bus sequence.
|
||||
Host byte inspection has no CPU execution restriction. CPU command writes may execute from ROM.
|
||||
|
||||
WAITCNT bits 0–1 select save wait states 4, 3, 2, or 8.
|
||||
The nominal byte-access costs are therefore 5, 4, 3, or 9 cycles, for both sequential and non-sequential requests.
|
||||
Save waits do not alter ROM wait fields. Flash data accesses cancel Game Pak opcode prefetch through the existing nominal model.
|
||||
Changing only save wait bits preserves the queue until a cartridge access cancels it.
|
||||
These costs are source-backed estimates, not physical timing measurements.
|
||||
|
||||
## Commands
|
||||
|
||||
Use these byte addresses and values for the unlock prefix:
|
||||
|
||||
1. Write `0xaa` to `0x0e005555`.
|
||||
2. Write `0x55` to `0x0e002aaa`.
|
||||
3. Write a command byte to `0x0e005555`.
|
||||
|
||||
Supported commands after the prefix:
|
||||
|
||||
| Command | Behavior |
|
||||
| --- | --- |
|
||||
| `0x90` | Enter chip-identification mode |
|
||||
| `0xf0` | Exit identification mode and return to array reads |
|
||||
| `0xb0` | On Flash128 only, accept a bank byte next at `0x0e000000` |
|
||||
|
||||
In ID mode, byte zero is the manufacturer and byte one is the device:
|
||||
|
||||
| Selection | Manufacturer | Device | Combined ID |
|
||||
| --- | --- | --- | --- |
|
||||
| Flash64 | `0xc2` | `0x1c` | `0x1cc2` |
|
||||
| Flash128 | `0xc2` | `0x09` | `0x09c2` |
|
||||
|
||||
Other ID-mode addresses remain diagnostic because their values are not established by this subset.
|
||||
Array mode reads bytes from the selected 64 KiB bank. Flash64 always uses bank zero.
|
||||
Flash128 accepts bank values zero and one only. Bank changes do not alter stored data.
|
||||
Entering and leaving ID mode preserves the selected bank.
|
||||
Reads during an incomplete unlock retain the previous read mode and bank.
|
||||
|
||||
For the documented 64 KiB Macronix device, a direct `0xf0` write at `0x0e005555` resets command/ID state.
|
||||
For Flash128, the same write is accepted only as a redundant reset when already idle in array mode.
|
||||
This bounded no-op matches the inspected emulators' idle behavior. It does not establish direct ID exit or busy-command cancellation.
|
||||
Flash128 still requires the full unlock prefix to exit ID mode. Direct reset during an incomplete unlock remains diagnostic.
|
||||
No matching manufacturer datasheet or physical measurement was used to claim broader 128 KiB reset behavior.
|
||||
|
||||
`0xa0` byte-program setup and `0x80` erase setup remain diagnostic at the command write.
|
||||
No operation starts, data changes, busy state, completion flag, or interrupt is fabricated.
|
||||
Unknown commands, invalid prefixes, and invalid bank writes are also diagnostic.
|
||||
Rejected accesses retain the previous command state and bytes, so retrying the same access gives the same result.
|
||||
This atomic diagnostic policy does not reproduce hardware handling of every malformed sequence.
|
||||
|
||||
## Transactions and validation
|
||||
|
||||
The small Flash controller state joins the existing cartridge machine-step transaction.
|
||||
The full save image stays outside the copied controller state; this read-only subset never mutates it during emulation.
|
||||
Failed CPU or DMA steps discard speculative controller changes and timing.
|
||||
Block-store preflight rejects a wide Flash destination before committing earlier RAM or device writes.
|
||||
HALT/STOP and elapsed cycles cannot create Flash completion events. There is no pending program or erase operation to finish.
|
||||
|
||||
Original tests cover both device IDs, every byte in both banks, exact image lengths, erased state, invalid sequences, and unchanged ROM/save data.
|
||||
They distinguish redundant idle reset from unsupported Flash128 ID/partial-command reset.
|
||||
ARM/Thumb probes verify ROM command writes, RAM byte reads, wait settings, restrictions, and retryable failed steps.
|
||||
Additional tests cover staged ID reads, block rollback, DMA rejection, GPIO/RTC independence, and prefetch cancellation.
|
||||
Desktop tests execute an original IWRAM byte reader with explicit device selection in terminal and native-window modes.
|
||||
No game code, save file, or copyrighted assets are included in these tests.
|
||||
|
||||
## Remaining work
|
||||
|
||||
Implement and validate program/erase commands, busy polling, cancellation, and byte-program bit transitions before claiming save functionality.
|
||||
Then add explicit host save loading and safe persistence, with exact-size validation and restart tests.
|
||||
Do not overwrite existing files or add immediate-success responses merely to pass a game check.
|
||||
|
||||
## References
|
||||
|
||||
- [GBATEK backup Flash](https://problemkaputt.de/gbatek-gba-cart-backup-flash-rom.htm): capacities, IDs, unlock sequences, bank selection, 64 KiB Macronix reset, byte-only access, and RAM-execution requirements.
|
||||
- [GBATEK](https://mgba-emu.github.io/gbatek/), WAITCNT section: save wait fields and one-cycle-plus-wait timing.
|
||||
- [mGBA savedata at 3a5e34be](https://github.com/mgba-emu/mgba/blob/3a5e34be33dc7f8f707e5bc9db69e8a430046f21/src/gba/savedata.c): comparison for controller phases, bank addressing, ID overlays, and idle reset handling. Its default chip IDs differ; its write/erase timing and busy approximation are not copied.
|
||||
- [ares Flash at 9408cb43](https://github.com/ares-emulator/ares/blob/9408cb43d4948fc3ea6e152a307a34348df3fe04/ares/gba/cartridge/flash.cpp): comparison for IDs, banking, unlocked ID exit, and unchanged idle state after an unrecognized direct reset. Its immediate program/erase behavior and permissive unlock handling are not adopted.
|
||||
Loading…
Add table
Add a link
Reference in a new issue