diff --git a/src/core/core.h b/src/core/core.h index aaf010e5b..148d92faa 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -9,6 +9,7 @@ #include "util/common.h" struct VFile; +struct mRTCSource; struct mCore { void* cpu; @@ -37,6 +38,8 @@ struct mCore { int32_t (*frameCounter)(struct mCore*); int32_t (*frameCycles)(struct mCore*); int32_t (*frequency)(struct mCore*); + + void (*setRTC)(struct mCore*, struct mRTCSource*); }; #endif diff --git a/src/gb/core.c b/src/gb/core.c index 554f24dc3..b20dc1bf6 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -114,6 +114,11 @@ static int32_t _GBCoreFrequency(struct mCore* core) { return DMG_LR35902_FREQUENCY; } +static void _GBCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { + struct GB* gb = core->board; + gb->memory.rtc = rtc; +} + struct mCore* GBCoreCreate(void) { struct GBCore* gbcore = malloc(sizeof(*gbcore)); struct mCore* core = &gbcore->d; @@ -134,5 +139,6 @@ struct mCore* GBCoreCreate(void) { core->frameCounter = _GBCoreFrameCounter; core->frameCycles = _GBCoreFrameCycles; core->frequency = _GBCoreFrequency; + core->setRTC = _GBCoreSetRTC; return core; } diff --git a/src/gb/memory.c b/src/gb/memory.c index c89735def..dc7d61313 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -5,11 +5,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "memory.h" +#include "core/interface.h" #include "gb/gb.h" #include "gb/io.h" #include "util/memory.h" +#include + mLOG_DEFINE_CATEGORY(GB_MBC); mLOG_DEFINE_CATEGORY(GB_MEM); @@ -55,6 +58,11 @@ void GBMemoryInit(struct GB* gb) { memset(gb->memory.hram, 0, sizeof(gb->memory.hram)); + gb->memory.sramAccess = false; + gb->memory.rtcAccess = false; + gb->memory.rtcLatched = 0; + gb->memory.rtc = NULL; + GBIOInit(gb); } @@ -152,7 +160,9 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) { return gb->video.vram[address & (GB_SIZE_VRAM - 1)]; case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: - if (memory->sramAccess) { + if (memory->rtcAccess) { + return gb->memory.rtcRegs[memory->activeRtcReg]; + } else if (memory->sramAccess) { return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; } return 0xFF; @@ -206,7 +216,9 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) { return; case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM + 1: - if (memory->sramAccess) { + if (memory->rtcAccess) { + gb->memory.rtcRegs[memory->activeRtcReg] = value; + } else if (memory->sramAccess) { gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value; } return; @@ -316,6 +328,27 @@ static void _switchSramBank(struct GBMemory* memory, int bank) { memory->sramCurrentBank = bank; } +static void _latchRtc(struct GBMemory* memory) { + time_t t; + struct mRTCSource* rtc = memory->rtc; + if (rtc) { + if (rtc->sample) { + rtc->sample(rtc); + } + t = rtc->unixTime(rtc); + } else { + t = time(0); + } + struct tm date; + localtime_r(&t, &date); + memory->rtcRegs[0] = date.tm_sec; + memory->rtcRegs[1] = date.tm_min; + memory->rtcRegs[2] = date.tm_hour; + memory->rtcRegs[3] = date.tm_yday; // TODO: Persist day counter + memory->rtcRegs[4] &= 0xF0; + memory->rtcRegs[4] |= date.tm_yday >> 8; +} + void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) { int bank = value & 0x1F; switch (address >> 13) { @@ -334,7 +367,6 @@ void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) { break; } break; - break; case 0x1: if (!bank) { ++bank; @@ -379,13 +411,18 @@ void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) { case 0x2: if (value < 4) { _switchSramBank(memory, value); - } else { - mLOG(GB_MBC, STUB, "MBC3 RTC unimplemented", value); + memory->rtcAccess = false; + } else if (value >= 8 && value <= 0xC) { + memory->activeRtcReg = value - 8; + memory->rtcAccess = true; } break; - default: - // TODO - mLOG(GB_MBC, STUB, "MBC3 unknown address: %04X:%02X", address, value); + case 0x3: + if (memory->rtcLatched && value == 0) { + memory->rtcLatched = value; + } else if (!memory->rtcLatched && value == 1) { + _latchRtc(memory); + } break; } } diff --git a/src/gb/memory.h b/src/gb/memory.h index 6a22c141f..fb4fd2eab 100644 --- a/src/gb/memory.h +++ b/src/gb/memory.h @@ -95,6 +95,12 @@ struct GBMemory { int dmaRemaining; size_t romSize; + + bool rtcAccess; + int activeRtcReg; + int rtcLatched; + uint8_t rtcRegs[5]; + struct mRTCSource* rtc; }; void GBMemoryInit(struct GB* gb);