GB MBC: Fix RTC initialization (fixes #825)

This commit is contained in:
Vicki Pfau 2017-07-29 20:32:13 -07:00
parent 558a3ab037
commit a330df2f1f
3 changed files with 294 additions and 2 deletions

View File

@ -18,6 +18,7 @@ Bugfixes:
- Qt: Fix LOG argument order
- GB Memory: Prevent accessing empty SRAM (fixes mgba.io/i/831)
- GB, GBA: Fix crashes when attempting to identify null VFiles
- GB MBC: Fix RTC initialization (fixes mgba.io/i/825)
Misc:
- GBA Timer: Use global cycles for timers
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)

View File

@ -255,6 +255,15 @@ void GBMBCInit(struct GB* gb) {
gb->memory.rtcAccess = false;
gb->memory.activeRtcReg = 0;
gb->memory.rtcLatched = false;
gb->memory.rtcLastLatch = 0;
if (gb->memory.rtc) {
if (gb->memory.rtc->sample) {
gb->memory.rtc->sample(gb->memory.rtc);
}
gb->memory.rtcLastLatch = gb->memory.rtc->unixTime(gb->memory.rtc);
} else {
gb->memory.rtcLastLatch = time(0);
}
memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
GBResizeSram(gb, gb->sramSize);
@ -993,7 +1002,7 @@ void GBMBCRTCWrite(struct GB* gb) {
STORE_32LE(gb->memory.rtcRegs[2], 0, &rtcBuffer.latchedHour);
STORE_32LE(gb->memory.rtcRegs[3], 0, &rtcBuffer.latchedDays);
STORE_32LE(gb->memory.rtcRegs[4], 0, &rtcBuffer.latchedDaysHi);
STORE_64LE(rtcLastLatch, 0, &rtcBuffer.unixTime);
STORE_64LE(gb->memory.rtcLastLatch, 0, &rtcBuffer.unixTime);
if (vf->size(vf) == gb->sramSize) {
// Writing past the end of the file can invalidate the file mapping

View File

@ -14,6 +14,7 @@
struct GBRTCTest {
struct mRTCSource d;
struct mCore* core;
struct VFile* fakeSave;
time_t nextTime;
};
@ -52,6 +53,9 @@ M_TEST_SUITE_SETUP(GBRTC) {
test->core->loadROM(test->core, vf);
mCoreSetRTC(test->core, &test->d);
test->fakeSave = VFileMemChunk(NULL, 0);
test->core->loadSave(test->core, test->fakeSave);
struct GB* gb = test->core->board;
gb->memory.mbcType = GB_MBC3_RTC;
@ -81,6 +85,7 @@ M_TEST_DEFINE(create) {
M_TEST_DEFINE(tickSecond) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 1;
@ -108,6 +113,7 @@ M_TEST_DEFINE(tickSecond) {
M_TEST_DEFINE(tick30Seconds) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 30;
@ -142,6 +148,7 @@ M_TEST_DEFINE(tick30Seconds) {
M_TEST_DEFINE(tickMinute) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 60;
@ -184,6 +191,7 @@ M_TEST_DEFINE(tickMinute) {
M_TEST_DEFINE(tick90Seconds) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 90;
@ -240,6 +248,7 @@ M_TEST_DEFINE(tick90Seconds) {
M_TEST_DEFINE(tick30Minutes) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 1800;
@ -282,6 +291,7 @@ M_TEST_DEFINE(tick30Minutes) {
M_TEST_DEFINE(tickHour) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600;
@ -339,6 +349,7 @@ M_TEST_DEFINE(tickHour) {
M_TEST_DEFINE(tick12Hours) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600 * 12;
@ -407,6 +418,7 @@ M_TEST_DEFINE(tick12Hours) {
M_TEST_DEFINE(tickDay) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600 * 24;
@ -505,6 +517,7 @@ M_TEST_DEFINE(tickDay) {
M_TEST_DEFINE(wideTickDay) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 3600 * 24 * 2001;
@ -611,6 +624,7 @@ M_TEST_DEFINE(wideTickDay) {
M_TEST_DEFINE(rolloverSecond) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->core->reset(test->core);
struct GB* gb = test->core->board;
test->nextTime = 1;
@ -672,6 +686,270 @@ M_TEST_DEFINE(rolloverSecond) {
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
}
M_TEST_DEFINE(roundtrip0) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->fakeSave->truncate(test->fakeSave, 0);
test->core->reset(test->core);
struct GB* gb = test->core->board;
uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
memset(gb->memory.rtcRegs, 0, sizeof(expected));
GBMBCRTCWrite(gb);
GBMBCRTCRead(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCWrite(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCRead(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600;
expected[2] = 1;
GBMBCRTCWrite(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCWrite(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600 * 2;
expected[2] = 2;
GBMBCRTCWrite(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
}
M_TEST_DEFINE(roundtripSecond) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->fakeSave->truncate(test->fakeSave, 0);
test->core->reset(test->core);
struct GB* gb = test->core->board;
uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
memset(gb->memory.rtcRegs, 0, sizeof(expected));
GBMBCRTCWrite(gb);
test->nextTime = 1;
GBMBCRTCRead(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
expected[0] = 1;
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCWrite(gb);
test->nextTime = 2;
GBMBCRTCRead(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
_sampleRtcKeepLatch(gb);
expected[0] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->core->reset(test->core);
expected[0] = 1;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
_sampleRtcKeepLatch(gb);
expected[0] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->core->reset(test->core);
expected[0] = 1;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
expected[0] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3;
test->core->reset(test->core);
expected[0] = 1;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
_sampleRtcKeepLatch(gb);
expected[0] = 3;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 1;
test->core->reset(test->core);
expected[0] = 1;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 4;
_sampleRtcKeepLatch(gb);
expected[0] = 4;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
}
M_TEST_DEFINE(roundtripDay) {
struct GBRTCTest* test = *state;
test->nextTime = 0;
test->fakeSave->truncate(test->fakeSave, 0);
test->core->reset(test->core);
struct GB* gb = test->core->board;
uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
memset(gb->memory.rtcRegs, 0, sizeof(expected));
GBMBCRTCWrite(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600 * 24;
GBMBCRTCRead(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 1;
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600 * 24 * 2;
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCWrite(gb);
test->nextTime = 3600 * 24 * 2;
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600 * 24 * 3;
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 3;
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600 * 24 * 2;
test->core->reset(test->core);
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 3600 * 24 * 3;
test->core->reset(test->core);
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 3;
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
}
M_TEST_DEFINE(roundtripHuge) {
struct GBRTCTest* test = *state;
test->nextTime = 1500000000;
test->fakeSave->truncate(test->fakeSave, 0);
test->core->reset(test->core);
struct GB* gb = test->core->board;
uint8_t expected[sizeof(gb->memory.rtcRegs)] = { 0, 0, 0, 0, 0 };
memset(gb->memory.rtcRegs, 0, sizeof(expected));
GBMBCRTCWrite(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 1500000000 + 3600 * 24;
GBMBCRTCRead(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 1;
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 1500000000 + 3600 * 24 * 2;
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
GBMBCRTCWrite(gb);
test->nextTime = 1500000000 + 3600 * 24 * 2;
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 1500000000 + 3600 * 24 * 3;
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 3;
GBMBCRTCRead(gb);
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 1500000000 + 3600 * 24 * 2;
test->core->reset(test->core);
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
test->nextTime = 1500000000 + 3600 * 24 * 3;
test->core->reset(test->core);
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 2;
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
expected[0] = 0;
expected[1] = 0;
expected[2] = 0;
expected[3] = 3;
_sampleRtcKeepLatch(gb);
assert_memory_equal(gb->memory.rtcRegs, expected, sizeof(expected));
}
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBRTC,
cmocka_unit_test(create),
cmocka_unit_test(tickSecond),
@ -683,4 +961,8 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBRTC,
cmocka_unit_test(tick12Hours),
cmocka_unit_test(tickDay),
cmocka_unit_test(wideTickDay),
cmocka_unit_test(rolloverSecond))
cmocka_unit_test(rolloverSecond),
cmocka_unit_test(roundtrip0),
cmocka_unit_test(roundtripSecond),
cmocka_unit_test(roundtripDay),
cmocka_unit_test(roundtripHuge))