mirror of
https://github.com/LIJI32/SameBoy.git
synced 2026-10-12 02:06:38 +00:00
API to detect MBC RAM activity, more frequent battery saves in Cocoa and SDL
This commit is contained in:
+17
-1
@@ -67,6 +67,9 @@
|
||||
NSTimer *_consoleOutputTimer;
|
||||
NSTimer *_hexTimer;
|
||||
|
||||
NSTimer *_batterySaveTimer;
|
||||
bool _dirtyBattery;
|
||||
|
||||
bool _fullScreen;
|
||||
bool _inSyncInput;
|
||||
NSString *_debuggerCommandWhilePaused;
|
||||
@@ -503,6 +506,9 @@ static void debuggerReloadCallback(GB_gameboy_t *gb)
|
||||
_hexTimer = [NSTimer timerWithTimeInterval:0.25 target:self selector:@selector(reloadMemoryView) userInfo:nil repeats:true];
|
||||
[[NSRunLoop mainRunLoop] addTimer:_hexTimer forMode:NSDefaultRunLoopMode];
|
||||
|
||||
_batterySaveTimer = [NSTimer timerWithTimeInterval:0.25 target:self selector:@selector(batteryTimerExpired) userInfo:nil repeats:true];
|
||||
[[NSRunLoop mainRunLoop] addTimer:_batterySaveTimer forMode:NSDefaultRunLoopMode];
|
||||
|
||||
/* Clear pending alarms, don't play alarms while playing */
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GBNotificationsUsed"]) {
|
||||
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
||||
@@ -580,6 +586,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
- (void)postRun
|
||||
{
|
||||
[_hexTimer invalidate];
|
||||
[_batterySaveTimer invalidate];
|
||||
[_audioLock lock];
|
||||
_audioBufferPosition = _audioBufferNeeded = 0;
|
||||
[_audioLock signal];
|
||||
@@ -808,6 +815,16 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
}
|
||||
}
|
||||
|
||||
- (void)batteryTimerExpired
|
||||
{
|
||||
if (_dirtyBattery && !GB_get_battery_dirty(&_gb)) {
|
||||
GB_save_battery(&_gb, self.savPath.UTF8String);
|
||||
}
|
||||
|
||||
_dirtyBattery = GB_get_battery_dirty(&_gb);
|
||||
GB_clear_battery_dirty(&_gb);
|
||||
}
|
||||
|
||||
- (NSFont *)debuggerFontOfSize:(unsigned)size
|
||||
{
|
||||
if (!size) {
|
||||
@@ -835,7 +852,6 @@ again:;
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
||||
- (void)updateFonts
|
||||
{
|
||||
_hexController.font = [self debuggerFontOfSize:12];
|
||||
|
||||
@@ -2032,6 +2032,17 @@ void GB_get_rom_title(GB_gameboy_t *gb, char *title)
|
||||
}
|
||||
}
|
||||
|
||||
bool GB_get_battery_dirty(GB_gameboy_t *gb)
|
||||
{
|
||||
if (GB_save_battery_size(gb) == 0) return false;
|
||||
return gb->battery_dirty;
|
||||
}
|
||||
|
||||
void GB_clear_battery_dirty(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->battery_dirty = false;
|
||||
}
|
||||
|
||||
uint32_t GB_get_rom_crc32(GB_gameboy_t *gb)
|
||||
{
|
||||
static const uint32_t table[] = {
|
||||
|
||||
@@ -841,6 +841,7 @@ struct GB_gameboy_internal_s {
|
||||
GB_rumble_mode_t rumble_mode;
|
||||
uint32_t rumble_on_cycles;
|
||||
uint32_t rumble_off_cycles;
|
||||
bool battery_dirty;
|
||||
|
||||
/* Temporary state */
|
||||
bool wx_just_changed;
|
||||
@@ -1009,6 +1010,10 @@ uint32_t GB_get_clock_rate(GB_gameboy_t *gb);
|
||||
uint32_t GB_get_unmultiplied_clock_rate(GB_gameboy_t *gb);
|
||||
void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier);
|
||||
|
||||
/* Checks if the ROM has modified battery-backed data since the last call to GB_clear_battery_dirty */
|
||||
bool GB_get_battery_dirty(GB_gameboy_t *gb);
|
||||
void GB_clear_battery_dirty(GB_gameboy_t *gb);
|
||||
|
||||
/* Handy ROM info APIs */
|
||||
// `title` must be at least 17 bytes in size
|
||||
void GB_get_rom_title(GB_gameboy_t *gb, char *title);
|
||||
|
||||
@@ -865,6 +865,7 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
break;
|
||||
case 0x6000: case 0x7000:
|
||||
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
|
||||
gb->battery_dirty = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -976,9 +977,11 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
break;
|
||||
case 0x10:
|
||||
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
|
||||
gb->battery_dirty = true;
|
||||
break;
|
||||
case 0x11: {
|
||||
memcpy(&gb->rtc_real, &gb->rtc_latched, sizeof(gb->rtc_real));
|
||||
gb->battery_dirty = true;
|
||||
break;
|
||||
}
|
||||
case 0x14:
|
||||
@@ -1045,13 +1048,16 @@ static bool huc3_write(GB_gameboy_t *gb, uint8_t value)
|
||||
else if (gb->huc3.access_index >= 0x58 && gb->huc3.access_index <= 0x5A) {
|
||||
gb->huc3.alarm_minutes &= ~(0xF << ((gb->huc3.access_index - 0x58) * 4));
|
||||
gb->huc3.alarm_minutes |= ((value & 0xF) << ((gb->huc3.access_index - 0x58) * 4));
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
else if (gb->huc3.access_index >= 0x5B && gb->huc3.access_index <= 0x5E) {
|
||||
gb->huc3.alarm_days &= ~(0xF << ((gb->huc3.access_index - 0x5B) * 4));
|
||||
gb->huc3.alarm_days |= ((value & 0xF) << ((gb->huc3.access_index - 0x5B) * 4));
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
else if (gb->huc3.access_index == 0x5F) {
|
||||
gb->huc3.alarm_enabled = value & 1;
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
else {
|
||||
// GB_log(gb, "Attempting to write %x to unsupported HuC-3 register: %03x\n", value & 0xF, gb->huc3.access_index);
|
||||
@@ -1157,6 +1163,7 @@ static void write_mbc7_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
// WRITE
|
||||
if (gb->mbc7.eeprom_write_enabled) {
|
||||
((uint16_t *)gb->mbc_ram)[gb->mbc7.eeprom_command & 0x7F] = 0;
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
gb->mbc7.argument_bits_left = 16;
|
||||
// We still need to process this command, don't erase eeprom_command
|
||||
@@ -1168,6 +1175,7 @@ static void write_mbc7_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
// ERASE
|
||||
if (gb->mbc7.eeprom_write_enabled) {
|
||||
((uint16_t *)gb->mbc_ram)[gb->mbc7.eeprom_command & 0x7F] = 0xFFFF;
|
||||
gb->battery_dirty = true;
|
||||
gb->mbc7.read_bits = 0x3FFF; // Emulate some time to settle
|
||||
}
|
||||
gb->mbc7.eeprom_command = 0;
|
||||
@@ -1177,6 +1185,7 @@ static void write_mbc7_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
if (gb->mbc7.eeprom_write_enabled) {
|
||||
memset(gb->mbc_ram, 0xFF, gb->mbc_ram_size);
|
||||
((uint16_t *)gb->mbc_ram)[gb->mbc7.eeprom_command & 0x7F] = 0xFFFF;
|
||||
gb->battery_dirty = true;
|
||||
gb->mbc7.read_bits = 0xFF; // Emulate some time to settle
|
||||
}
|
||||
gb->mbc7.eeprom_command = 0;
|
||||
@@ -1185,6 +1194,7 @@ static void write_mbc7_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
// WRAL (WRite ALl)
|
||||
if (gb->mbc7.eeprom_write_enabled) {
|
||||
memset(gb->mbc_ram, 0, gb->mbc_ram_size);
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
gb->mbc7.argument_bits_left = 16;
|
||||
// We still need to process this command, don't erase eeprom_command
|
||||
@@ -1201,11 +1211,13 @@ static void write_mbc7_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
if (gb->mbc7.eeprom_command & 0x100) {
|
||||
// WRITE
|
||||
((uint16_t *)gb->mbc_ram)[gb->mbc7.eeprom_command & 0x7F] |= bit;
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
else {
|
||||
// WRAL
|
||||
for (unsigned i = 0; i < 0x7F; i++) {
|
||||
((uint16_t *)gb->mbc_ram)[i] |= bit;
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1291,6 +1303,7 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
}
|
||||
|
||||
gb->mbc_ram[((addr & 0x1FFF) + effective_bank * 0x2000) & (gb->mbc_ram_size - 1)] = value;
|
||||
gb->battery_dirty = true;
|
||||
}
|
||||
|
||||
static void write_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
|
||||
+22
@@ -37,6 +37,8 @@ static typeof(free) *free_function = NULL;
|
||||
static char *battery_save_path_ptr = NULL;
|
||||
static SDL_GLContext gl_context = NULL;
|
||||
static bool console_supported = false;
|
||||
static bool battery_dirty = false;
|
||||
static unsigned battery_timer = 0;
|
||||
|
||||
bool uses_gl(void)
|
||||
{
|
||||
@@ -433,6 +435,9 @@ static void handle_events(GB_gameboy_t *gb)
|
||||
break;
|
||||
case HOTKEY_PAUSE:
|
||||
paused = !paused;
|
||||
if (paused) {
|
||||
GB_save_battery(gb, battery_save_path_ptr);
|
||||
}
|
||||
break;
|
||||
case HOTKEY_MUTE:
|
||||
GB_audio_set_paused(GB_audio_is_playing());
|
||||
@@ -582,6 +587,9 @@ static void handle_events(GB_gameboy_t *gb)
|
||||
case SDL_SCANCODE_P:
|
||||
if (event.key.keysym.mod & MODIFIER) {
|
||||
paused = !paused;
|
||||
if (paused) {
|
||||
GB_save_battery(gb, battery_save_path_ptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_SCANCODE_M:
|
||||
@@ -758,6 +766,20 @@ static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type)
|
||||
}
|
||||
}
|
||||
do_rewind = rewind_down;
|
||||
|
||||
battery_timer++;
|
||||
if (battery_timer == 15) {
|
||||
battery_timer = 0;
|
||||
|
||||
if (battery_dirty && !GB_get_battery_dirty(gb)) {
|
||||
GB_save_battery(gb, battery_save_path_ptr);
|
||||
GB_log(gb, "Saved\n");
|
||||
}
|
||||
|
||||
battery_dirty = GB_get_battery_dirty(gb);
|
||||
GB_clear_battery_dirty(gb);
|
||||
}
|
||||
|
||||
handle_events(gb);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user