mirror of
https://github.com/libretro/mgba.git
synced 2024-11-27 10:11:00 +00:00
GB MBC: Fix RTC initialization (fixes #825)
This commit is contained in:
parent
558a3ab037
commit
a330df2f1f
1
CHANGES
1
CHANGES
@ -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)
|
||||
|
11
src/gb/mbc.c
11
src/gb/mbc.c
@ -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
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user