# Game Save System Implementation Plan (RP2350/RP2040) This document outlines the strategy for implementing non-volatile game save states using the onboard Flash memory. ## 1. Objectives * **Persistence:** Save game state so progress is kept after power-off. * **Multi-game Support:** Allow multiple games to have independent saves without overwriting each other. * **Safety:** Ensure flash writes don't interfere with program execution or interrupt handlers. * **Wear Leveling:** Minimize unnecessary writes to prolong flash lifespan. ## 2. Flash Memory Mapping The RP2350 on this board has 8MB of Flash memory mapped starting at `XIP_BASE` (`0x10000000`). We will reserve the top section for data. | Memory Range | Purpose | Size | | :--- | :--- | :--- | | `0x10000000 - 0x106FFFFF` | Program Code, Fonts, Assets | 7MB | | `0x10700000 - 0x107EFFFF` | Reserved/Future | 960KB | | `0x107F0000 - 0x107F0FFF` | **Save Registry** | 4KB (1 Sector) | | `0x107F1000 - 0x107FFFFF` | **Game Save Slots** | 60KB (15 Slots) | ## 3. Architecture Components ### A. `PersistentStorage` Manager (`lib/persistent_storage.h`) A singleton or static helper class that handles raw flash operations. * `bool save_exists(const char* game_id)` * `bool save_data(const char* game_id, void* data, size_t size)` * `bool load_data(const char* game_id, void* buffer, size_t size)` ### B. Updated `Game` Interface (`lib/game.h`) Add methods to the base class to standardize how state is handled. ```cpp virtual const char* get_game_id() const = 0; virtual size_t get_save_data(void* buffer, size_t max_size) = 0; virtual void load_save_data(const void* buffer, size_t size) = 0; ``` ### C. Save Registry To avoid collisions, the first sector (`0x107F0000`) will store a lookup table: ```cpp struct RegistryEntry { char game_id[16]; uint32_t sector_index; uint32_t data_size; uint32_t checksum; }; ``` ## 4. Implementation Steps 1. **Create `PersistentStorage`:** * Implement flash sector erasing and programming using `pico/flash.h`. * Include interrupt protection using `save_and_disable_interrupts()`. 2. **Update `Game` Base Class:** * Modify `lib/game.h` to include the virtual persistence methods. 3. **Implement in Monopoly:** * Create a `MonopolySaveState` struct (POD - Plain Old Data). * Populate it from game variables in `get_save_data`. 4. **Integrate with Launcher:** * Modify `GameLauncher` to check for existing saves when a game is selected. * Modify the main loop to trigger `save_data` at logical points (e.g., end of turn/exit). ## 5. Collision Avoidance Logic * When a game requests a save for the first time, the `PersistentStorage` manager scans the Registry. * If the `game_id` isn't found, it allocates the next available 4KB sector. * It writes the specific `game_id` and its assigned `sector_index` back to the Registry sector. * Sequential saves for that ID will always use that specific sector. ## 6. Important Notes * **Flash Wear:** Each sector supports ~100k erase cycles. Total lifespan depends on frequency of saves. * **Alignment:** Data must be programmed in multiples of `FLASH_PAGE_SIZE` (256 bytes). * **Recursion:** Never call flash functions from within an interrupt or callback that might be triggered during a write.