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
This commit is contained in:
negativeExponent 2021-05-24 09:11:48 +08:00
parent 685a495d5c
commit 05a046e7ed
4 changed files with 113 additions and 22 deletions

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)