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 "stdafx.h"
#include "GBCart.h" #include "GBCart.h"
#include <time.h>
static void read_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, uint8_t* data) static void read_gb_cart_normal(struct gb_cart* gb_cart, uint16_t address, uint8_t* data)
{ {
uint16_t offset; 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) 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) else if (gb_cart->has_rtc)
{ {
switch (gb_cart->ram_bank) if (gb_cart->rtc_latch)
{ {
case 0x08: for (int i = 0; i < 32; i++)
data[0] = gb_cart->rtc_latch_second; {
break; data[i] = gb_cart->rtc_latch_data[gb_cart->ram_bank - 0x08];
case 0x09: }
data[0] = gb_cart->rtc_latch_minute; }
break; else
case 0x0A: {
data[0] = gb_cart->rtc_latch_hour; memoryUpdateMBC3Clock(gb_cart);
break; for (int i = 0; i < 32; i++)
case 0x0B: {
data[0] = gb_cart->rtc_latch_day; data[i] = gb_cart->rtc_data[gb_cart->ram_bank - 0x08];
break; }
case 0x0C:
data[0] = (gb_cart->rtc_latch_day_carry << 7) | (gb_cart->rtc_latch_day >> 8);
break;
} }
} }
} }
@ -320,11 +357,12 @@ static void write_gb_cart_mbc3(struct gb_cart* gb_cart, uint16_t address, const
//Implement RTC timer / latch //Implement RTC timer / latch
if (gb_cart->rtc_latch == 0 && data[0] == 1) if (gb_cart->rtc_latch == 0 && data[0] == 1)
{ {
gb_cart->rtc_latch_second = gb_cart->rtc_second; //Update time
gb_cart->rtc_latch_minute = gb_cart->rtc_minute; memoryUpdateMBC3Clock(gb_cart);
gb_cart->rtc_latch_hour = gb_cart->rtc_hour; for (int i = 0; i < 4; i++)
gb_cart->rtc_latch_day = gb_cart->rtc_day; {
gb_cart->rtc_latch_day_carry = gb_cart->rtc_day_carry; gb_cart->rtc_latch_data[i] = gb_cart->rtc_data[i];
}
} }
gb_cart->rtc_latch = data[0]; 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) else if (gb_cart->has_rtc)
{ {
bank = data[0];
/* RTC write */ /* RTC write */
switch (gb_cart->ram_bank) gb_cart->rtc_data[gb_cart->ram_bank - 0x08] = data[0];
{
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;
}
} }
} }
} }
@ -724,11 +736,6 @@ bool GBCart::init_gb_cart(struct gb_cart* gb_cart, const char* gb_file)
if (ram_size != 0) if (ram_size != 0)
{ {
if (type->extra_devices & GED_RTC)
{
ram_size += 0x30;
}
ram.reset(new uint8_t[ram_size]); ram.reset(new uint8_t[ram_size]);
if (ram.get() == NULL) 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.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 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) if (type->extra_devices & GED_RTC)
{ {
gbCartRTC rtc; tempFile.Read(&gb_cart->rtc_data[0], 4);
memcpy(&rtc, &ram.get()[ram_size-0x30], 0x30); tempFile.Read(&gb_cart->rtc_data[1], 4);
tempFile.Read(&gb_cart->rtc_data[2], 4);
gb_cart->rtc_second = rtc.second; tempFile.Read(&gb_cart->rtc_data[3], 4);
gb_cart->rtc_minute = rtc.minute; tempFile.Read(&gb_cart->rtc_data[4], 4);
gb_cart->rtc_hour = rtc.hour; tempFile.Read(&gb_cart->rtc_latch_data[0], 4);
gb_cart->rtc_day = rtc.day; tempFile.Read(&gb_cart->rtc_latch_data[1], 4);
gb_cart->rtc_day_carry = rtc.day_carry; tempFile.Read(&gb_cart->rtc_latch_data[2], 4);
gb_cart->rtc_latch_second = rtc.latch_second; tempFile.Read(&gb_cart->rtc_latch_data[3], 4);
gb_cart->rtc_latch_minute = rtc.latch_minute; tempFile.Read(&gb_cart->rtc_latch_data[4], 4);
gb_cart->rtc_latch_hour = rtc.latch_hour; tempFile.Read(&gb_cart->rtc_last_time, 8);
gb_cart->rtc_latch_day = rtc.latch_day; memoryUpdateMBC3Clock(gb_cart);
gb_cart->rtc_latch_day_carry = rtc.latch_day_carry;
gb_cart->rtc_last_time = rtc.mapperLastTime;
} }
tempFile.Close();
} }
/* update gb_cart */ /* update gb_cart */
gb_cart->ram = ram.release();
gb_cart->rom = rom.release(); gb_cart->rom = rom.release();
gb_cart->ram = ram.release();
gb_cart->rom_size = rom_size; gb_cart->rom_size = rom_size;
gb_cart->ram_size = ram_size; gb_cart->ram_size = ram_size;
gb_cart->rom_bank = 1; gb_cart->rom_bank = 1;
@ -782,28 +787,21 @@ void GBCart::save_gb_cart(struct gb_cart* gb_cart)
{ {
CFile ramFile; CFile ramFile;
ramFile.Open(g_Settings->LoadStringVal(Game_Transferpak_Sav).c_str(), CFileBase::modeWrite | CFileBase::modeCreate); 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) if (gb_cart->has_rtc)
{ {
ramFile.Write(gb_cart->ram, gb_cart->ram_size - 0x30); ramFile.Write(&gb_cart->rtc_data[0], 4);
ramFile.Write(&gb_cart->rtc_data[1], 4);
gbCartRTC rtc; ramFile.Write(&gb_cart->rtc_data[2], 4);
rtc.second = gb_cart->rtc_second; ramFile.Write(&gb_cart->rtc_data[3], 4);
rtc.minute = gb_cart->rtc_minute; ramFile.Write(&gb_cart->rtc_data[4], 4);
rtc.hour = gb_cart->rtc_hour; ramFile.Write(&gb_cart->rtc_latch_data[0], 4);
rtc.day = gb_cart->rtc_day; ramFile.Write(&gb_cart->rtc_latch_data[1], 4);
rtc.day_carry = gb_cart->rtc_day_carry; ramFile.Write(&gb_cart->rtc_latch_data[2], 4);
rtc.latch_second = gb_cart->rtc_latch_second; ramFile.Write(&gb_cart->rtc_latch_data[3], 4);
rtc.latch_minute = gb_cart->rtc_latch_minute; ramFile.Write(&gb_cart->rtc_latch_data[4], 4);
rtc.latch_hour = gb_cart->rtc_latch_hour; ramFile.Write(&gb_cart->rtc_last_time, 8);
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.Close(); ramFile.Close();

View File

@ -30,36 +30,14 @@ struct gb_cart
uint32_t rtc_latch; uint32_t rtc_latch;
uint32_t rtc_second; int32_t rtc_data[5];
uint32_t rtc_minute; int32_t rtc_latch_data[5];
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;
time_t rtc_last_time; time_t rtc_last_time;
void(*read_gb_cart)(struct gb_cart* gb_cart, uint16_t address, uint8_t* data); 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); 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 class GBCart
{ {
public: public: