From 05a046e7edb86ee9dfd8f0a92e15a0312df797f4 Mon Sep 17 00:00:00 2001 From: negativeExponent Date: Mon, 24 May 2021 09:11:48 +0800 Subject: [PATCH] HuC3: Enable battery save, update RTC support - SRAM support is already available, but the battery-enabled flag was not enable for 0xFE (HuC3) rom types. - Hookup rtc support based on local time. This would allow time to sync when starting the game. You need to initially set the time first though on first bootup (RTC support was based on gambatte sources) Fix https://github.com/libretro/vbam-libretro/issues/95 --- src/gb/GB.cpp | 2 + src/gb/gbMemory.cpp | 94 ++++++++++++++++++++++++++++++++------- src/gb/gbMemory.h | 22 ++++++--- src/libretro/libretro.cpp | 17 ++++++- 4 files changed, 113 insertions(+), 22 deletions(-) diff --git a/src/gb/GB.cpp b/src/gb/GB.cpp index 16517d37..f571d2c1 100644 --- a/src/gb/GB.cpp +++ b/src/gb/GB.cpp @@ -4376,6 +4376,7 @@ bool gbUpdateSizes() case 0x1e: case 0x22: case 0xfd: + case 0xfe: case 0xff: gbBattery = 1; break; @@ -4399,6 +4400,7 @@ bool gbUpdateSizes() case 0x0f: case 0x10: // mbc3 case 0xfd: // tama5 + case 0xfe: gbRTCPresent = 1; break; default: diff --git a/src/gb/gbMemory.cpp b/src/gb/gbMemory.cpp index d1a6e61e..02a559fc 100644 --- a/src/gb/gbMemory.cpp +++ b/src/gb/gbMemory.cpp @@ -1000,14 +1000,33 @@ mapperHuC3 gbDataHuC3 = { 0, // RAM read value 0, // Register 1 0, // Register 2 - 0, // Register 3 - 0, // Register 4 - 0, // Register 5 - 0, // Register 6 - 0, // Register 7 - 0 // Register 8 + 0, // DateTime + 0, // WritingTime + 0, // ModeFlag + 0, // ClockShift + 0 // lastTime }; +void memoryupdateHuC3Latch() { + uint64_t now = time(NULL); + uint64_t diff = now - gbDataHuC3.mapperLastTime; + + if (diff > 0) { + unsigned minute = (diff / 60) % 1440; + unsigned day = (diff / 86400) & 0xFFF; + + gbDataHuC3.mapperDateTime = (day << 12) | minute; + } +} + +void memoryupdateHuC3Clock() { + uint64_t now = time(NULL); + unsigned minute = (gbDataHuC3.mapperWritingTime & 0xFFF) % 1440; + unsigned day = (gbDataHuC3.mapperWritingTime & 0xFFF000) >> 12; + + gbDataHuC3.mapperLastTime = now - minute * 60 - day * 86400; +} + // HuC3 ROM write registers void mapperHuC3ROM(uint16_t address, uint8_t value) { @@ -1066,7 +1085,7 @@ uint8_t mapperHuC3ReadRAM(uint16_t address) // HuC3 RAM write void mapperHuC3RAM(uint16_t address, uint8_t value) { - int* p; + //int* p; if (gbDataHuC3.mapperRAMFlag < 0x0b || gbDataHuC3.mapperRAMFlag > 0x0e) { if (gbDataHuC3.mapperRAMEnable) { @@ -1082,20 +1101,43 @@ void mapperHuC3RAM(uint16_t address, uint8_t value) } else { switch (value & 0xf0) { case 0x10: - p = &gbDataHuC3.mapperRegister2; + /*p = &gbDataHuC3.mapperRegister2; gbDataHuC3.mapperRAMValue = *(p + gbDataHuC3.mapperRegister1++); if (gbDataHuC3.mapperRegister1 > 6) - gbDataHuC3.mapperRegister1 = 0; + gbDataHuC3.mapperRegister1 = 0;*/ + + // read time + memoryupdateHuC3Latch(); + if (gbDataHuC3.mapperModeFlag == HUC3_READ) { + gbDataHuC3.mapperRAMValue = (gbDataHuC3.mapperDateTime >> gbDataHuC3.mapperClockShift) & 0x0F; + gbDataHuC3.mapperClockShift += 4; + if (gbDataHuC3.mapperClockShift > 24) + gbDataHuC3.mapperClockShift = 0; + } break; case 0x30: - p = &gbDataHuC3.mapperRegister2; + /*p = &gbDataHuC3.mapperRegister2; *(p + gbDataHuC3.mapperRegister1++) = value & 0x0f; if (gbDataHuC3.mapperRegister1 > 6) gbDataHuC3.mapperRegister1 = 0; - gbDataHuC3.mapperAddress = (gbDataHuC3.mapperRegister6 << 24) | (gbDataHuC3.mapperRegister5 << 16) | (gbDataHuC3.mapperRegister4 << 8) | (gbDataHuC3.mapperRegister3 << 4) | (gbDataHuC3.mapperRegister2); + gbDataHuC3.mapperAddress = (gbDataHuC3.mapperRegister6 << 24) | (gbDataHuC3.mapperRegister5 << 16) | (gbDataHuC3.mapperRegister4 << 8) | (gbDataHuC3.mapperRegister3 << 4) | (gbDataHuC3.mapperRegister2);*/ + + // write time + if (gbDataHuC3.mapperModeFlag == HUC3_WRITE) { + if (gbDataHuC3.mapperClockShift == 0) + gbDataHuC3.mapperWritingTime = 0; + if (gbDataHuC3.mapperClockShift <= 24) { + gbDataHuC3.mapperWritingTime |= (value & 0x0F) << gbDataHuC3.mapperClockShift; + gbDataHuC3.mapperClockShift += 4; + if (gbDataHuC3.mapperClockShift == 24) { + memoryupdateHuC3Clock(); + gbDataHuC3.mapperModeFlag = HUC3_READ; + } + } + } break; case 0x40: - gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) | (value & 0x0f); + /*gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) | (value & 0x0f); gbDataHuC3.mapperRegister2 = (gbDataHuC3.mapperAddress & 0x0f); gbDataHuC3.mapperRegister3 = ((gbDataHuC3.mapperAddress >> 4) & 0x0f); gbDataHuC3.mapperRegister4 = ((gbDataHuC3.mapperAddress >> 8) & 0x0f); @@ -1103,13 +1145,35 @@ void mapperHuC3RAM(uint16_t address, uint8_t value) gbDataHuC3.mapperRegister6 = ((gbDataHuC3.mapperAddress >> 24) & 0x0f); gbDataHuC3.mapperRegister7 = 0; gbDataHuC3.mapperRegister8 = 0; - gbDataHuC3.mapperRAMValue = 0; + gbDataHuC3.mapperRAMValue = 0;*/ + + // some kind of mode shift + switch(value & 0x0F) { + case 0x0: + // shift reset? + gbDataHuC3.mapperClockShift = 0; + break; + case 0x3: + // write time? + gbDataHuC3.mapperModeFlag = HUC3_WRITE; + gbDataHuC3.mapperClockShift = 0; + break; + case 0x7: + gbDataHuC3.mapperModeFlag = HUC3_READ; + gbDataHuC3.mapperClockShift = 0; + break; + // others are unimplemented so far + } break; case 0x50: - gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) | ((value << 4) & 0x0f); + //gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) | ((value << 4) & 0x0f); + break; + case 0x60: + gbDataHuC3.mapperModeFlag = HUC3_READ; // ??? + gbDataHuC3.mapperRAMValue = 1; break; default: - gbDataHuC3.mapperRAMValue = 1; + //gbDataHuC3.mapperRAMValue = 1; break; } } diff --git a/src/gb/gbMemory.h b/src/gb/gbMemory.h index 0ca97506..e901be0b 100644 --- a/src/gb/gbMemory.h +++ b/src/gb/gbMemory.h @@ -77,6 +77,12 @@ struct mapperHuC1 { int mapperRAMAddress; }; +enum { + HUC3_READ = 0, + HUC3_WRITE = 1, + HUC3_NONE = 2 +}; + struct mapperHuC3 { int mapperRAMEnable; int mapperROMBank; @@ -87,12 +93,14 @@ struct mapperHuC3 { int mapperRAMValue; int mapperRegister1; int mapperRegister2; - int mapperRegister3; - int mapperRegister4; - int mapperRegister5; - int mapperRegister6; - int mapperRegister7; - int mapperRegister8; + int mapperDateTime; + int mapperWritingTime; + int mapperModeFlag; + int mapperClockShift; + union { + time_t mapperLastTime; + uint64_t _time_pad; /* so that 32bit and 64bit saves are compatible */ + }; }; struct mapperTAMA5 { @@ -196,4 +204,6 @@ extern void memoryUpdateMapGS3(); #define TAMA5_RTC_DATA_SIZE sizeof(int) * 14 + sizeof(uint64_t) +#define HUC3_RTC_DATA_SIZE sizeof(int) * 4 + sizeof(uint64_t) + #endif // GBMEMORY_H diff --git a/src/libretro/libretro.cpp b/src/libretro/libretro.cpp index 61d3ef05..2b3508ec 100644 --- a/src/libretro/libretro.cpp +++ b/src/libretro/libretro.cpp @@ -161,6 +161,9 @@ static void set_gbPalette(void) } } +extern void memoryupdateHuC3Clock(); +extern void memoryupdateHuC3Latch(); + static void* gb_rtcdata_prt(void) { switch (gbRomType) { @@ -169,6 +172,8 @@ static void* gb_rtcdata_prt(void) return &gbDataMBC3.mapperSeconds; case 0xfd: // TAMA5 + extended return &gbDataTAMA5.mapperSeconds; + case 0xfe: // HuC3 + Clock + return &gbDataHuC3.mapperDateTime; } return NULL; } @@ -181,6 +186,8 @@ static size_t gb_rtcdata_size(void) return MBC3_RTC_DATA_SIZE; case 0xfd: // TAMA5 + extended return TAMA5_RTC_DATA_SIZE; + case 0xfe: // HuC3 + Clock + return HUC3_RTC_DATA_SIZE; } return 0; } @@ -231,6 +238,10 @@ static void gbInitRTC(void) gbDataTAMA5.mapperControl = (gbDataTAMA5.mapperControl & 0xfe) | (lt->tm_yday > 255 ? 1 : 0); } break; + case 0xfe: + //memoryupdateHuC3Clock(); + memoryupdateHuC3Latch(); + break; } } @@ -298,7 +309,7 @@ void* retro_get_memory_data(unsigned id) data = (gbCgbMode ? gbVram : (gbMemory + 0x8000)); break; case RETRO_MEMORY_RTC: - if (gbBattery && gbRTCPresent) + //if (gbBattery/* && gbRTCPresent*/) data = gb_rtcdata_prt(); break; } @@ -1425,6 +1436,10 @@ void retro_run(void) if (!gbDataTAMA5.mapperLastTime) initRTC = true; break; + case 0xfe: + if (!gbDataHuC3.mapperLastTime) + initRTC = true; + break; } /* Initialize RTC using local time if needed */ if (initRTC)