From ee4907949b3ab3581214fa9f43ec7ec4155fc3ee Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sun, 21 Aug 2016 22:33:57 +0300 Subject: [PATCH] Support for RTC latching. Fixes #4. --- Core/gb.c | 6 +++--- Core/gb.h | 15 ++++++++------- Core/memory.c | 14 +++++++++----- Core/timing.c | 22 +++++++++++----------- 4 files changed, 31 insertions(+), 26 deletions(-) diff --git a/Core/gb.c b/Core/gb.c index 8e83532..76ccf87 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -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; diff --git a/Core/gb.h b/Core/gb.h index 4c3fe93..18a78ab 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -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 */ diff --git a/Core/memory.c b/Core/memory.c index 77dbfb4..d8719c8 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -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) { diff --git a/Core/timing.c b/Core/timing.c index 48f28dc..24f7da7 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -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; } } }