Support for RTC latching. Fixes #4.

This commit is contained in:
Lior Halphon 2016-08-21 22:33:57 +03:00
parent 92c2b22735
commit ee4907949b
4 changed files with 31 additions and 26 deletions

View File

@ -369,7 +369,7 @@ int GB_save_battery(GB_gameboy_t *gb, const char *path)
return EIO;
}
if (gb->cartridge_type->has_rtc) {
if (fwrite(gb->rtc_data, 1, sizeof(gb->rtc_data), f) != sizeof(gb->rtc_data)) {
if (fwrite(&gb->rtc_real, 1, sizeof(gb->rtc_real), f) != sizeof(gb->rtc_real)) {
fclose(f);
return EIO;
}
@ -397,7 +397,7 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path)
goto reset_rtc;
}
if (fread(gb->rtc_data, 1, sizeof(gb->rtc_data), f) != sizeof(gb->rtc_data)) {
if (fread(&gb->rtc_real, 1, sizeof(gb->rtc_real), f) != sizeof(gb->rtc_real)) {
goto reset_rtc;
}
@ -418,7 +418,7 @@ void GB_load_battery(GB_gameboy_t *gb, const char *path)
goto exit;
reset_rtc:
gb->last_rtc_second = time(NULL);
gb->rtc_high |= 0x80; /* This gives the game a hint that the clock should be reset. */
gb->rtc_real.high |= 0x80; /* This gives the game a hint that the clock should be reset. */
exit:
fclose(f);
return;

View File

@ -306,15 +306,16 @@ typedef struct GB_gameboy_s {
GB_SECTION(rtc,
union {
struct {
uint8_t rtc_seconds;
uint8_t rtc_minutes;
uint8_t rtc_hours;
uint8_t rtc_days;
uint8_t rtc_high;
uint8_t seconds;
uint8_t minutes;
uint8_t hours;
uint8_t days;
uint8_t high;
};
uint8_t rtc_data[5];
};
uint8_t data[5];
} rtc_real, rtc_latched;
time_t last_rtc_second;
bool rtc_latch;
);
/* Video Display */

View File

@ -78,8 +78,8 @@ static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
/* RTC read */
gb->rtc_high |= ~0xC1; /* Not all bytes in RTC high are used. */
return gb->rtc_data[gb->mbc_ram_bank - 8];
gb->rtc_latched.high |= ~0xC1; /* Not all bytes in RTC high are used. */
return gb->rtc_latched.data[gb->mbc_ram_bank - 8];
}
if (!gb->mbc_ram) {
@ -284,7 +284,12 @@ static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
case 0x2000: case 0x3000: gb->mbc3.rom_bank = value; break;
case 0x4000: case 0x5000: gb->mbc3.ram_bank = value; break;
case 0x6000: case 0x7000: /* Todo: Clock latching support */ break;
case 0x6000: case 0x7000:
if (!gb->rtc_latch && (value & 1)) { /* Todo: verify condition is correct*/
memcpy(&gb->rtc_latched, &gb->rtc_real, sizeof(gb->rtc_real));
}
gb->rtc_latch = value & 1;
break;
}
break;
case GB_MBC5:
@ -314,8 +319,7 @@ static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
/* RTC read */
gb->rtc_data[gb->mbc_ram_bank - 8] = value;
gb->rtc_high |= ~0xC1; /* Not all bytes in RTC high are used. */
gb->rtc_latched.data[gb->mbc_ram_bank - 8] = gb->rtc_real.data[gb->mbc_ram_bank - 8] = value; /* Todo: does it really write both? */
}
if (gb->cartridge_type->mbc_type == GB_MBC2) {

View File

@ -114,26 +114,26 @@ void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
void GB_rtc_run(GB_gameboy_t *gb)
{
if ((gb->rtc_high & 0x40) == 0) { /* is timer running? */
if ((gb->rtc_real.high & 0x40) == 0) { /* is timer running? */
time_t current_time = time(NULL);
while (gb->last_rtc_second < current_time) {
gb->last_rtc_second++;
if (++gb->rtc_seconds == 60)
if (++gb->rtc_real.seconds == 60)
{
gb->rtc_seconds = 0;
if (++gb->rtc_minutes == 60)
gb->rtc_real.seconds = 0;
if (++gb->rtc_real.minutes == 60)
{
gb->rtc_minutes = 0;
if (++gb->rtc_hours == 24)
gb->rtc_real.minutes = 0;
if (++gb->rtc_real.hours == 24)
{
gb->rtc_hours = 0;
if (++gb->rtc_days == 0)
gb->rtc_real.hours = 0;
if (++gb->rtc_real.days == 0)
{
if (gb->rtc_high & 1) /* Bit 8 of days*/
if (gb->rtc_real.high & 1) /* Bit 8 of days*/
{
gb->rtc_high |= 0x80; /* Overflow bit */
gb->rtc_real.high |= 0x80; /* Overflow bit */
}
gb->rtc_high ^= 1;
gb->rtc_real.high ^= 1;
}
}
}