diff --git a/src/gb/gb.c b/src/gb/gb.c index 28ceaf483..008586465 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -23,6 +23,8 @@ const uint32_t SGB_LR35902_FREQUENCY = 0x418B1E; const uint32_t GB_COMPONENT_MAGIC = 0x400000; +static const uint8_t _knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66}; + #define DMG_BIOS_CHECKSUM 0xC2F5CC97 #define DMG_2_BIOS_CHECKSUM 0x59C8598E #define CGB_BIOS_CHECKSUM 0x41884E46 @@ -271,6 +273,18 @@ void GBUnloadROM(struct GB* gb) { gb->sramVf = NULL; } +void GBSynthesizeROM(struct VFile* vf) { + if (!vf) { + return; + } + const struct GBCartridge cart = { + .logo = { _knownHeader[0], _knownHeader[1], _knownHeader[2], _knownHeader[3]} + }; + + vf->seek(vf, 0x100, SEEK_SET); + vf->write(vf, &cart, sizeof(cart)); +} + void GBLoadBIOS(struct GB* gb, struct VFile* vf) { gb->biosVf = vf; } @@ -618,12 +632,11 @@ void GBIllegal(struct LR35902Core* cpu) { bool GBIsROM(struct VFile* vf) { vf->seek(vf, 0x104, SEEK_SET); uint8_t header[4]; - static const uint8_t knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66}; if (vf->read(vf, &header, sizeof(header)) < (ssize_t) sizeof(header)) { return false; } - if (memcmp(header, knownHeader, sizeof(header))) { + if (memcmp(header, _knownHeader, sizeof(header))) { return false; } return true; diff --git a/src/gb/gb.h b/src/gb/gb.h index 87a6223e6..ed1f5b726 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -118,6 +118,7 @@ bool GBLoadROM(struct GB* gb, struct VFile* vf); bool GBLoadSave(struct GB* gb, struct VFile* vf); void GBYankROM(struct GB* gb); void GBUnloadROM(struct GB* gb); +void GBSynthesizeROM(struct VFile* vf); bool GBIsBIOS(struct VFile* vf); void GBLoadBIOS(struct GB* gb, struct VFile* vf); diff --git a/src/gb/test/core.c b/src/gb/test/core.c index 6aba3898e..c5ed2fdfa 100644 --- a/src/gb/test/core.c +++ b/src/gb/test/core.c @@ -7,6 +7,8 @@ #include "core/core.h" #include "gb/core.h" +#include "gb/gb.h" +#include "util/vfs.h" M_TEST_DEFINE(create) { struct mCore* core = GBCoreCreate(); @@ -18,7 +20,7 @@ M_TEST_DEFINE(create) { M_TEST_DEFINE(platform) { struct mCore* core = GBCoreCreate(); assert_non_null(core); - assert_true(core->platform(core) == PLATFORM_GB); + assert_int_equal(core->platform(core), PLATFORM_GB); assert_true(core->init(core)); core->deinit(core); } @@ -40,8 +42,20 @@ M_TEST_DEFINE(loadNullROM) { core->deinit(core); } +M_TEST_DEFINE(isROM) { + struct VFile* vf = VFileMemChunk(NULL, 2048); + GBSynthesizeROM(vf); + assert_true(GBIsROM(vf)); + struct mCore* core = mCoreFindVF(vf); + assert_non_null(core); + assert_int_equal(core->platform(core), PLATFORM_GB); + assert_true(core->init(core)); + core->deinit(core); +} + M_TEST_SUITE_DEFINE(GBCore, cmocka_unit_test(create), cmocka_unit_test(platform), cmocka_unit_test(reset), - cmocka_unit_test(loadNullROM)) + cmocka_unit_test(loadNullROM), + cmocka_unit_test(isROM)) diff --git a/src/gb/test/gb.c b/src/gb/test/gb.c index d637c3aea..6e289ec3d 100644 --- a/src/gb/test/gb.c +++ b/src/gb/test/gb.c @@ -6,9 +6,11 @@ #include "util/test/suite.h" M_TEST_SUITE_DECLARE(GBCore); +M_TEST_SUITE_DECLARE(GBMBC); int TestRunGB(void) { int failures = 0; failures += M_TEST_SUITE_RUN(GBCore); + failures += M_TEST_SUITE_RUN(GBMBC); return failures; } diff --git a/src/gb/test/mbc.c b/src/gb/test/mbc.c new file mode 100644 index 000000000..d4e94b401 --- /dev/null +++ b/src/gb/test/mbc.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/test/suite.h" + +#include "core/core.h" +#include "gb/core.h" +#include "gb/gb.h" +#include "gb/mbc.h" +#include "util/vfs.h" + +M_TEST_SUITE_SETUP(GBMBC) { + struct VFile* vf = VFileMemChunk(NULL, 2048); + GBSynthesizeROM(vf); + struct mCore* core = GBCoreCreate(); + core->init(core); + core->loadROM(core, vf); + *state = core; + return 0; +} + +M_TEST_SUITE_TEARDOWN(GBMBC) { + if (!*state) { + return 0; + } + struct mCore* core = *state; + core->deinit(core); + return 0; +} +M_TEST_DEFINE(detectNone) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x00; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC_NONE); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x08; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC_NONE); + + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x09; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC_NONE); + + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x0A; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC_NONE); +} + +M_TEST_DEFINE(detect1) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x00; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC1); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x01; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC1); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x02; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC1); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x03; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC1); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x04; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC1); +} + +M_TEST_DEFINE(detect2) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x04; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC2); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x05; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC2); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x06; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC2); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x07; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC2); +} + +M_TEST_DEFINE(detect3) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x0E; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC3); + assert_int_not_equal(gb->memory.mbcType, GB_MBC3_RTC); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x0F; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC3_RTC); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x10; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC3_RTC); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x11; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC3); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x12; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC3); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x13; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC3); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x14; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC3); + assert_int_not_equal(gb->memory.mbcType, GB_MBC3_RTC); +} + +M_TEST_DEFINE(detect5) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x19; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC5); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x1A; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC5); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x1B; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC5); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x1C; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC5_RUMBLE); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x1D; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC5_RUMBLE); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x1E; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC5_RUMBLE); +} + +M_TEST_DEFINE(detect6) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x1F; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC6); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x20; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC6); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x21; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC6); +} + +M_TEST_DEFINE(detect7) { + struct mCore* core = *state; + struct GB* gb = core->board; + struct GBCartridge* cart = (struct GBCartridge*) &gb->memory.rom[0x100]; + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x21; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC7); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x22; + core->reset(core); + assert_int_equal(gb->memory.mbcType, GB_MBC7); + + gb->memory.mbcType = GB_MBC_AUTODETECT; + cart->type = 0x23; + core->reset(core); + assert_int_not_equal(gb->memory.mbcType, GB_MBC7); +} + +M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(GBMBC, + cmocka_unit_test(detectNone), + cmocka_unit_test(detect1), + cmocka_unit_test(detect2), + cmocka_unit_test(detect3), + cmocka_unit_test(detect5), + cmocka_unit_test(detect6), + cmocka_unit_test(detect7)) diff --git a/src/util/test/suite.h b/src/util/test/suite.h index 5a2e0429b..ea1888553 100644 --- a/src/util/test/suite.h +++ b/src/util/test/suite.h @@ -14,14 +14,21 @@ #define M_TEST_SUITE(NAME) _testSuite_ ## NAME #define M_TEST_SUITE_RUN(NAME) printf("\nRunning suite %s\n", # NAME), M_TEST_SUITE(NAME)() -#define M_TEST_SUITE_DEFINE(NAME, ...) \ +#define M_TEST_SUITE_DEFINE(NAME, ...) M_TEST_SUITE_DEFINE_EX(NAME, NULL, NULL, __VA_ARGS__) +#define M_TEST_SUITE_DEFINE_SETUP(NAME, ...) M_TEST_SUITE_DEFINE_EX(NAME, _testSuite_setup_ ## NAME, NULL, __VA_ARGS__) +#define M_TEST_SUITE_DEFINE_TEARDOWN(NAME, ...) M_TEST_SUITE_DEFINE_EX(NAME, NULL, _testSuite_teardown_ ## NAME, __VA_ARGS__) +#define M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(NAME, ...) M_TEST_SUITE_DEFINE_EX(NAME, _testSuite_setup_ ## NAME, _testSuite_teardown_ ## NAME, __VA_ARGS__) +#define M_TEST_SUITE_DEFINE_EX(NAME, SETUP, TEARDOWN, ...) \ int M_TEST_SUITE(NAME) (void) { \ const static struct CMUnitTest tests[] = { \ __VA_ARGS__ \ }; \ - return cmocka_run_group_tests_name(# NAME, tests, NULL, NULL); \ + return cmocka_run_group_tests_name(# NAME, tests, SETUP, TEARDOWN); \ } +#define M_TEST_SUITE_SETUP(NAME) static int _testSuite_setup_ ## NAME (void **state ATTRIBUTE_UNUSED) +#define M_TEST_SUITE_TEARDOWN(NAME) static int _testSuite_teardown_ ## NAME (void **state ATTRIBUTE_UNUSED) + #define M_TEST_SUITE_DECLARE(NAME) extern int M_TEST_SUITE(NAME) (void) #endif