Skip to content

Commit 51b290e

Browse files
JoeMattclaude
andcommitted
Address review: preserve saves across soft reset, sync on write
- EepromReset/MTReset: preserve save data across soft resets, only reset the state machine (fixes data loss on retro_reset) - EEPROMSave: sync save buffer on every EEPROM write via eeprom_dirty_cb so frontends that cache the pointer see fresh data - Remove cdromEEPROM from save buffer (not wired to any emulation code, was always 0xFF) — save size is now 128 bytes - EepromInit/MTInit: only blank memory on first power-on, not on subsequent calls Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 0505cdd commit 51b290e

3 files changed

Lines changed: 63 additions & 35 deletions

File tree

libretro.c

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,21 @@ int game_width = 0;
3131
int game_height = 0;
3232

3333
extern uint16_t eeprom_ram[64];
34-
extern uint16_t cdromEEPROM[64];
3534
extern uint8_t mtMem[0x20000];
3635
extern uint32_t jaguarMainROMCRC32;
36+
extern void (*eeprom_dirty_cb)(void);
3737

38-
/* Combined save buffer for RETRO_MEMORY_SAVE_RAM.
39-
* Layout: [cart EEPROM 128 bytes][CDROM EEPROM 128 bytes]
40-
* For Memory Track cart (CRC 0xFDF37F47): mtMem is used directly (128K).
38+
/* Save buffer for RETRO_MEMORY_SAVE_RAM.
39+
* Regular carts: 128 bytes (64 x 16-bit EEPROM words, big-endian packed).
40+
* Memory Track cart (CRC 0xFDF37F47): mtMem is used directly (128K).
4141
*
42-
* EEPROM data is stored big-endian on disk (high byte first per 16-bit word)
43-
* to match the Jaguar's native byte order. This is handled by pack/unpack
44-
* functions so the in-memory uint16_t arrays work on any host. */
45-
#define EEPROM_SAVE_SIZE 256 /* 128 bytes cart + 128 bytes CDROM */
42+
* The save buffer is kept in sync on every EEPROM write via eeprom_dirty_cb,
43+
* so frontends that cache the pointer always see current data. */
44+
#define EEPROM_SAVE_SIZE 128 /* 64 x 16-bit words, big-endian */
4645
#define MT_SAVE_SIZE 0x20000 /* 128K Memory Track */
4746
static uint8_t eeprom_save_buf[EEPROM_SAVE_SIZE];
47+
static void eeprom_pack_save_buf(void);
48+
static void eeprom_unpack_save_buf(void);
4849

4950
static retro_video_refresh_t video_cb;
5051
static retro_input_poll_t input_poll_cb;
@@ -976,6 +977,9 @@ bool retro_load_game(const struct retro_game_info *info)
976977

977978
check_variables();
978979

980+
/* Register EEPROM dirty callback so the save buffer stays in sync */
981+
eeprom_dirty_cb = eeprom_pack_save_buf;
982+
979983
JaguarInit(); // set up hardware
980984
memcpy(jagMemSpace + 0xE00000,
981985
((vjs.biosType == BT_K_SERIES) ? jaguarBootROM : jaguarBootROM2),
@@ -1031,6 +1035,9 @@ unsigned retro_api_version(void)
10311035

10321036
/* Pack EEPROM uint16_t arrays into the save buffer (big-endian).
10331037
* Called before the frontend reads save data. */
1038+
/* Pack eeprom_ram[] into the save buffer (big-endian byte order).
1039+
* Called on every EEPROM write via eeprom_dirty_cb so the buffer
1040+
* is always up-to-date for frontends that cache the pointer. */
10341041
static void eeprom_pack_save_buf(void)
10351042
{
10361043
unsigned i;
@@ -1039,24 +1046,16 @@ static void eeprom_pack_save_buf(void)
10391046
eeprom_save_buf[(i * 2) + 0] = eeprom_ram[i] >> 8;
10401047
eeprom_save_buf[(i * 2) + 1] = eeprom_ram[i] & 0xFF;
10411048
}
1042-
for (i = 0; i < 64; i++)
1043-
{
1044-
eeprom_save_buf[128 + (i * 2) + 0] = cdromEEPROM[i] >> 8;
1045-
eeprom_save_buf[128 + (i * 2) + 1] = cdromEEPROM[i] & 0xFF;
1046-
}
10471049
}
10481050

1049-
/* Unpack the save buffer back into EEPROM uint16_t arrays.
1050-
* Called after the frontend loads save data. */
1051+
/* Unpack the save buffer back into eeprom_ram[].
1052+
* Called once after the frontend loads .srm data. */
10511053
static void eeprom_unpack_save_buf(void)
10521054
{
10531055
unsigned i;
10541056
for (i = 0; i < 64; i++)
10551057
eeprom_ram[i] = ((uint16_t)eeprom_save_buf[(i * 2) + 0] << 8)
10561058
| eeprom_save_buf[(i * 2) + 1];
1057-
for (i = 0; i < 64; i++)
1058-
cdromEEPROM[i] = ((uint16_t)eeprom_save_buf[128 + (i * 2) + 0] << 8)
1059-
| eeprom_save_buf[128 + (i * 2) + 1];
10601059
}
10611060

10621061
void *retro_get_memory_data(unsigned type)
@@ -1068,8 +1067,7 @@ void *retro_get_memory_data(unsigned type)
10681067
/* Memory Track cart uses 128K NVRAM directly */
10691068
if (jaguarMainROMCRC32 == 0xFDF37F47)
10701069
return mtMem;
1071-
/* Regular carts: pack EEPROM into endian-safe buffer */
1072-
eeprom_pack_save_buf();
1070+
/* Regular carts: return the pre-packed save buffer */
10731071
return eeprom_save_buf;
10741072
}
10751073
return NULL;

src/eeprom.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
#include "eeprom.h"
1717

1818
#include <stdlib.h>
19+
#include <stdbool.h>
1920
#include <string.h> // For memset
2021

2122
uint16_t eeprom_ram[64];
22-
uint16_t cdromEEPROM[64];
23+
24+
/* Callback to sync the save buffer when EEPROM is modified.
25+
* Set by libretro.c to keep RETRO_MEMORY_SAVE_RAM up to date. */
26+
void (*eeprom_dirty_cb)(void) = NULL;
2327

2428
// Private function prototypes
2529
static void EEPROMSave(void);
@@ -45,31 +49,49 @@ static uint16_t jerry_writes_enabled = 0;
4549
static uint16_t jerry_ee_direct_jump = 0;
4650

4751

52+
static bool eeprom_initialized = false;
53+
4854
void EepromInit(void)
4955
{
50-
/* EEPROM data is now loaded/saved by the frontend via
51-
* retro_get_memory_data(RETRO_MEMORY_SAVE_RAM). No file I/O here. */
56+
/* On first init (power-on), fill EEPROM with 0xFF (blank state).
57+
* The frontend will overwrite this via RETRO_MEMORY_SAVE_RAM
58+
* before the first retro_run() if a save file exists. */
59+
if (!eeprom_initialized)
60+
{
61+
memset(eeprom_ram, 0xFF, 64 * sizeof(uint16_t));
62+
eeprom_initialized = true;
63+
}
5264
}
5365

5466

5567
void EepromReset(void)
5668
{
57-
/* Fill with 0xFF (blank EEPROM state). If the frontend has
58-
* previously saved data, it will overwrite this via the
59-
* RETRO_MEMORY_SAVE_RAM interface before the first frame. */
60-
memset(eeprom_ram, 0xFF, 64 * sizeof(uint16_t));
61-
memset(cdromEEPROM, 0xFF, 64 * sizeof(uint16_t));
69+
/* Preserve EEPROM contents across soft resets — save data must
70+
* survive retro_reset(). Only the state machine is reset. */
71+
jerry_ee_state = EE_STATE_START;
72+
jerry_ee_op = 0;
73+
jerry_ee_rstate = 0;
74+
jerry_ee_address_data = 0;
75+
jerry_ee_address_cnt = 6;
76+
jerry_ee_data = 0;
77+
jerry_ee_data_cnt = 16;
78+
jerry_writes_enabled = 0;
79+
jerry_ee_direct_jump = 0;
6280
}
6381

6482

6583
void EepromDone(void)
6684
{
85+
eeprom_initialized = false;
6786
}
6887

6988

7089
static void EEPROMSave(void)
7190
{
72-
/* No-op: the frontend persists SRAM via retro_get_memory_data. */
91+
/* Notify libretro.c to sync the save buffer so frontends that
92+
* cache the RETRO_MEMORY_SAVE_RAM pointer see fresh data. */
93+
if (eeprom_dirty_cb)
94+
eeprom_dirty_cb();
7395
}
7496

7597

src/memtrack.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,37 @@ enum { MT_IDLE, MT_PHASE1, MT_PHASE2 };
3232
uint8_t mtMem[0x20000];
3333
uint8_t mtCommand = MT_NONE;
3434
uint8_t mtState = MT_IDLE;
35+
static int mt_initialized = 0;
3536

3637
// Private function prototypes
3738
void MTStateMachine(uint8_t reg, uint16_t data);
3839

3940

4041
void MTInit(void)
4142
{
42-
/* Memory Track data is now loaded/saved by the frontend via
43-
* retro_get_memory_data(RETRO_MEMORY_SAVE_RAM). No file I/O here. */
43+
/* On first init (power-on), fill with 0xFF (blank NVRAM state).
44+
* The frontend will overwrite this via RETRO_MEMORY_SAVE_RAM
45+
* before the first retro_run() if a save file exists. */
46+
if (!mt_initialized)
47+
{
48+
memset(mtMem, 0xFF, 0x20000);
49+
mt_initialized = 1;
50+
}
4451
}
4552

4653

4754
void MTReset(void)
4855
{
49-
/* Fill with 0xFF (blank EEPROM state). If the frontend has
50-
* previously saved data, it will overwrite this via the
51-
* RETRO_MEMORY_SAVE_RAM interface before the first frame. */
52-
memset(mtMem, 0xFF, 0x20000);
56+
/* Preserve Memory Track contents across soft resets.
57+
* Only reset the command state machine. */
58+
mtCommand = MT_NONE;
59+
mtState = MT_IDLE;
5360
}
5461

5562

5663
void MTDone(void)
5764
{
65+
mt_initialized = 0;
5866
}
5967

6068

0 commit comments

Comments
 (0)