feat(cartridge): add 32 KiB SRAM save memory

Select it with --save-type sram (SaveDevice::Sram). The array is byte-wide,
starts erased, and repeats every 32 KiB through the 0x0e00xxxx save window.
A CPU byte store is staged and committed when its step completes, so failed
steps roll back and reads later in the step see the byte. Unlike Flash, SRAM
can be read from ROM code. Halfword/word access and DMA stay diagnostic until
the 8-bit bus behavior for those widths is verified.

SRAM shares the save-image API, host save files, and save states. Its device
code is new, so existing save states keep loading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhfHfHEuzv2AUTd6erW1gU
This commit is contained in:
0xrsydn 2026-10-14 11:51:27 +07:00
commit 32eaffa0fe
15 changed files with 405 additions and 30 deletions

View file

@ -35,7 +35,7 @@ Reads past supplied cartridge bytes remain explicit memory errors, not open-bus
All three Game Pak ROM windows use the same supplied bytes and existing wait-state rules.
Ordinary cartridge bytes remain read-only. CPU and DMA writes to the `0x08`–`0x0c` ROM windows pay their bus cost and are ignored, as on hardware.
Writes to the `0x0d` window remain `ReadOnly` diagnostics until EEPROM is modeled there. Host `Memory::write*` calls stay strict everywhere.
Optional `--save-type flash64` or `--save-type flash128` enables [nominal Flash programming, erase, and reads](saves.md).
Optional `--save-type flash64` or `--save-type flash128` enables [nominal Flash programming, erase, and reads](saves.md); `--save-type sram` selects [32 KiB SRAM](saves.md#sram).
Without `--save-file PATH`, changes remain volatile. With it, the frontend loads an exact-size image and persists changes on clean exit or when a ROM window ends on a diagnostic.
Missing images start erased. Existing images receive unique backups before replacement; incomplete Flash operations refuse persistence.
Read the [storage safeguards and limits](saves.md#desktop-persistence) before using a valuable save.

View file

@ -1,14 +1,15 @@
# Cartridge Flash and save files
# Cartridge Flash, SRAM, and save files
The core supports explicit Macronix Flash selection, identification, bank selection, byte programming, and sector/chip erase.
Operations complete after nominal delays and expose bounded data polling. They do not complete immediately on the command write.
The desktop can load and persist raw images through explicit `--save-file PATH` selection.
Original ROM tests verify save/restart/load across processes. Saving in an external game remains unverified.
SRAM, EEPROM, and other manufacturers' protocols remain separate work.
The core also supports explicit 32 KiB SRAM; see [SRAM](#sram).
EEPROM and other manufacturers' Flash protocols remain separate work.
## Selection and core API
Use `--save-type flash64` or `--save-type flash128` in terminal or window ROM modes.
Use `--save-type flash64`, `--save-type flash128`, or `--save-type sram` in terminal or window ROM modes.
Selection is independent of `--rtc`. Omitting the save type leaves save memory unmapped.
No filename, ROM signature, or first-write detection changes the selected device.
Without `--save-file`, the selected device starts erased (`0xff`) and all changes remain volatile.
@ -16,7 +17,7 @@ The ROM suite schema still has no save-selection or save-file field.
Core APIs on `Memory`:
- `set_save_device(SaveDevice)` selects `None`, `Flash64`, or `Flash128` and initializes an erased array.
- `set_save_device(SaveDevice)` selects `None`, `Flash64`, `Flash128`, or `Sram` and initializes an erased array.
GPIO/RTC state is preserved.
- `load_save_image(&[u8])` accepts exactly the selected capacity. It resets commands, pending operations, ID mode, bank, and modification tracking.
Invalid size or missing hardware changes nothing.
@ -29,6 +30,16 @@ Configuration, loading, and host inspection occur between machine steps.
The core has no file, clock, window, or host-audio dependency. Frontends supply image bytes and own durable storage.
A browser frontend can use the same API with browser storage instead of filesystem paths.
## SRAM
`SaveDevice::Sram` is a 32 KiB byte-wide array with no command protocol. It starts erased (`0xff`) like Flash.
The 32 KiB array repeats twice through the `0x0e000000..0x0e00ffff` save window; higher addresses stay unmapped.
CPU byte stores take effect when the instruction's step completes. Reads later in the same step already see the new byte.
Byte stores and loads may execute from ROM; the Flash work-RAM read restriction does not apply.
Halfword and word reads and writes, and DMA transfers, remain diagnostics until 8-bit bus behavior for those widths is verified.
SRAM shares the save window's WAITCNT wait states, save-image API, host persistence, and save states with Flash.
A save state records the selected device. Restoring it into a machine with another save device is rejected as a cartridge setup mismatch.
## Bus and commands
Only `0x0e000000` through `0x0e00ffff` are mapped. Accesses are byte-only.