Fix up reading and writing of the RTC data to the save file.

Correct the RTC emulation behaviour, made it more like NRAGES, various emulators i was basing mine off seemed to not correctly update the RTC.
This commit is contained in:
Emmet Young 2016-02-04 00:33:03 +11:00
parent dd7cf4af10
commit e6b1fd3aec
2 changed files with 89 additions and 113 deletions

View File

@ -11,6 +11,8 @@
#include "stdafx.h"
#include "GBCart.h"
#include <time.h>
static void read_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, uint8_t* data)
{
uint16_t offset;
@ -230,6 +232,44 @@ static void write_gb_cart_mbc2(struct gb_cart* gb_cart, uint16_t address, const
}
}
void memoryUpdateMBC3Clock(struct gb_cart* gb_cart)
{
time_t now = time(NULL);
time_t diff = now - gb_cart->rtc_last_time;
if (diff > 0) {
// update the clock according to the last update time
gb_cart->rtc_data[0] += (int)(diff % 60);
if (gb_cart->rtc_data[0] > 59) {
gb_cart->rtc_data[0] -= 60;
gb_cart->rtc_data[1]++;
}
diff /= 60;
gb_cart->rtc_data[1] += (int)(diff % 60);
if (gb_cart->rtc_data[1] > 59) {
gb_cart->rtc_data[1] -= 60;
gb_cart->rtc_data[2]++;
}
diff /= 60;
gb_cart->rtc_data[2] += (int)(diff % 24);
if (gb_cart->rtc_data[2] > 23) {
gb_cart->rtc_data[2] -= 24;
gb_cart->rtc_data[3]++;
}
diff /= 24;
gb_cart->rtc_data[3] += (int)(diff & 0xffffffff);
if (gb_cart->rtc_data[3] > 255) {
if (gb_cart->rtc_data[3] > 511) {
gb_cart->rtc_data[3] %= 512;
gb_cart->rtc_data[3] |= 0x80;
}
gb_cart->rtc_data[4] = (gb_cart->rtc_data[4] & 0xFE) | (gb_cart->rtc_data[3]>255 ? 1 : 0);
}
}
gb_cart->rtc_last_time = now;
}
static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t* data)
{
@ -261,23 +301,20 @@ static void read_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, uint8_t
}
else if (gb_cart->has_rtc)
{
switch (gb_cart->ram_bank)
if (gb_cart->rtc_latch)
{
case 0x08:
data[0] = gb_cart->rtc_latch_second;
break;
case 0x09:
data[0] = gb_cart->rtc_latch_minute;
break;
case 0x0A:
data[0] = gb_cart->rtc_latch_hour;
break;
case 0x0B:
data[0] = gb_cart->rtc_latch_day;
break;
case 0x0C:
data[0] = (gb_cart->rtc_latch_day_carry << 7) | (gb_cart->rtc_latch_day >> 8);
break;
for (int i = 0; i < 32; i++)
{
data[i] = gb_cart->rtc_latch_data[gb_cart->ram_bank - 0x08];
}
}
else
{
memoryUpdateMBC3Clock(gb_cart);
for (int i = 0; i < 32; i++)
{
data[i] = gb_cart->rtc_data[gb_cart->ram_bank - 0x08];
}
}
}
}
@ -320,11 +357,12 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const
//Implement RTC timer / latch
if (gb_cart->rtc_latch == 0 && data[0] == 1)
{
gb_cart->rtc_latch_second = gb_cart->rtc_second;
gb_cart->rtc_latch_minute = gb_cart->rtc_minute;
gb_cart->rtc_latch_hour = gb_cart->rtc_hour;
gb_cart->rtc_latch_day = gb_cart->rtc_day;
gb_cart->rtc_latch_day_carry = gb_cart->rtc_day_carry;
//Update time
memoryUpdateMBC3Clock(gb_cart);
for (int i = 0; i < 4; i++)
{
gb_cart->rtc_latch_data[i] = gb_cart->rtc_data[i];
}
}
gb_cart->rtc_latch = data[0];
}
@ -342,34 +380,8 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const
}
else if (gb_cart->has_rtc)
{
bank = data[0];
/* RTC write */
switch (gb_cart->ram_bank)
{
case 0x08:
if (bank >= 60)
bank = 0;
gb_cart->rtc_second = bank;
break;
case 0x09:
if (bank >= 60)
bank = 0;
gb_cart->rtc_minute = bank;
break;
case 0x0A:
if (bank >= 24)
bank = 0;
gb_cart->rtc_hour = bank;
break;
case 0x0B:
gb_cart->rtc_day = (gb_cart->rtc_day & 0x0100) | bank;
break;
case 0x0C:
gb_cart->rtc_day = ((bank & 1) << 8) | (gb_cart->rtc_day & 0xFF);
gb_cart->rtc_day_carry = bank & 0x80;
break;
}
gb_cart->rtc_data[gb_cart->ram_bank - 0x08] = data[0];
}
}
}
@ -724,11 +736,6 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file)
if (ram_size != 0)
{
if (type->extra_devices & GED_RTC)
{
ram_size += 0x30;
}
ram.reset(new uint8_t[ram_size]);
if (ram.get() == NULL)
{
@ -742,32 +749,30 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file)
}
tempFile.Read(ram.get(), ram_size);
tempFile.Close();
}
//If we have RTC we need to load in the data, we assume the save will use the VBA-M format
if (type->extra_devices & GED_RTC)
{
gbCartRTC rtc;
memcpy(&rtc, &ram.get()[ram_size-0x30], 0x30);
gb_cart->rtc_second = rtc.second;
gb_cart->rtc_minute = rtc.minute;
gb_cart->rtc_hour = rtc.hour;
gb_cart->rtc_day = rtc.day;
gb_cart->rtc_day_carry = rtc.day_carry;
gb_cart->rtc_latch_second = rtc.latch_second;
gb_cart->rtc_latch_minute = rtc.latch_minute;
gb_cart->rtc_latch_hour = rtc.latch_hour;
gb_cart->rtc_latch_day = rtc.latch_day;
gb_cart->rtc_latch_day_carry = rtc.latch_day_carry;
gb_cart->rtc_last_time = rtc.mapperLastTime;
tempFile.Read(&gb_cart->rtc_data[0], 4);
tempFile.Read(&gb_cart->rtc_data[1], 4);
tempFile.Read(&gb_cart->rtc_data[2], 4);
tempFile.Read(&gb_cart->rtc_data[3], 4);
tempFile.Read(&gb_cart->rtc_data[4], 4);
tempFile.Read(&gb_cart->rtc_latch_data[0], 4);
tempFile.Read(&gb_cart->rtc_latch_data[1], 4);
tempFile.Read(&gb_cart->rtc_latch_data[2], 4);
tempFile.Read(&gb_cart->rtc_latch_data[3], 4);
tempFile.Read(&gb_cart->rtc_latch_data[4], 4);
tempFile.Read(&gb_cart->rtc_last_time, 8);
memoryUpdateMBC3Clock(gb_cart);
}
tempFile.Close();
}
/* update gb_cart */
gb_cart->ram = ram.release();
gb_cart->rom = rom.release();
gb_cart->ram = ram.release();
gb_cart->rom_size = rom_size;
gb_cart->ram_size = ram_size;
gb_cart->rom_bank = 1;
@ -782,28 +787,21 @@ void GBCart::save_gb_cart(struct gb_cart* gb_cart)
{
CFile ramFile;
ramFile.Open(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), CFileBase::modeWrite | CFileBase::modeCreate);
ramFile.Write(gb_cart->ram, gb_cart->ram_size);
if (gb_cart->has_rtc)
{
ramFile.Write(gb_cart->ram, gb_cart->ram_size - 0x30);
gbCartRTC rtc;
rtc.second = gb_cart->rtc_second;
rtc.minute = gb_cart->rtc_minute;
rtc.hour = gb_cart->rtc_hour;
rtc.day = gb_cart->rtc_day;
rtc.day_carry = gb_cart->rtc_day_carry;
rtc.latch_second = gb_cart->rtc_latch_second;
rtc.latch_minute = gb_cart->rtc_latch_minute;
rtc.latch_hour = gb_cart->rtc_latch_hour;
rtc.latch_day = gb_cart->rtc_latch_day;
rtc.latch_day_carry = gb_cart->rtc_latch_day_carry;
rtc.mapperLastTime = gb_cart->rtc_last_time;
ramFile.Write(&rtc, 0x30);
}
else
{
ramFile.Write(gb_cart->ram, gb_cart->ram_size);
ramFile.Write(&gb_cart->rtc_data[0], 4);
ramFile.Write(&gb_cart->rtc_data[1], 4);
ramFile.Write(&gb_cart->rtc_data[2], 4);
ramFile.Write(&gb_cart->rtc_data[3], 4);
ramFile.Write(&gb_cart->rtc_data[4], 4);
ramFile.Write(&gb_cart->rtc_latch_data[0], 4);
ramFile.Write(&gb_cart->rtc_latch_data[1], 4);
ramFile.Write(&gb_cart->rtc_latch_data[2], 4);
ramFile.Write(&gb_cart->rtc_latch_data[3], 4);
ramFile.Write(&gb_cart->rtc_latch_data[4], 4);
ramFile.Write(&gb_cart->rtc_last_time, 8);
}
ramFile.Close();

View File

@ -30,36 +30,14 @@ struct gb_cart
uint32_t rtc_latch;
uint32_t rtc_second;
uint32_t rtc_minute;
uint32_t rtc_hour;
uint32_t rtc_day;
uint32_t rtc_day_carry;
uint32_t rtc_latch_second;
uint32_t rtc_latch_minute;
uint32_t rtc_latch_hour;
uint32_t rtc_latch_day;
uint32_t rtc_latch_day_carry;
int32_t rtc_data[5];
int32_t rtc_latch_data[5];
time_t rtc_last_time;
void(*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data);
void(*write_gb_cart)(struct gb_cart* gb_cart, uint16_t address, const uint8_t* data);
};
struct gbCartRTC {
uint32_t second;
uint32_t minute;
uint32_t hour;
uint32_t day;
uint32_t day_carry;
uint32_t latch_second;
uint32_t latch_minute;
uint32_t latch_hour;
uint32_t latch_day;
uint32_t latch_day_carry;
time_t mapperLastTime;
};
class GBCart
{
public: