diff --git a/CMakeLists.txt b/CMakeLists.txt index dac307a69..fe534eff6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ if(NOT LIBMGBA_ONLY) set(BUILD_TEST OFF CACHE BOOL "Build testing harness") set(BUILD_SUITE OFF CACHE BOOL "Build test suite") set(BUILD_CINEMA OFF CACHE BOOL "Build video tests suite") + set(BUILD_ROM_TEST OFF CACHE BOOL "Build ROM test tool") set(BUILD_EXAMPLE OFF CACHE BOOL "Build example frontends") set(BUILD_PYTHON OFF CACHE BOOL "Build Python bindings") set(BUILD_STATIC OFF CACHE BOOL "Build a static library") @@ -1222,12 +1223,14 @@ if(NOT QUIET AND NOT LIBMGBA_ONLY) message(STATUS "Frontends:") message(STATUS " Qt: ${BUILD_QT}") message(STATUS " SDL (${SDL_VERSION}): ${BUILD_SDL}") + message(STATUS " Python bindings: ${BUILD_PYTHON}") + message(STATUS " Examples: ${BUILD_EXAMPLE}") + message(STATUS "Test tools:") message(STATUS " Profiling: ${BUILD_PERF}") message(STATUS " Test harness: ${BUILD_TEST}") message(STATUS " Test suite: ${BUILD_SUITE}") message(STATUS " Video test suite: ${BUILD_CINEMA}") - message(STATUS " Python bindings: ${BUILD_PYTHON}") - message(STATUS " Examples: ${BUILD_EXAMPLE}") + message(STATUS " ROM tester: ${BUILD_ROM_TEST}") message(STATUS "Cores:") message(STATUS " Libretro core: ${BUILD_LIBRETRO}") if(APPLE) diff --git a/src/platform/test/rom-test-main.c b/src/platform/test/rom-test-main.c index d015f40c0..916df85b7 100644 --- a/src/platform/test/rom-test-main.c +++ b/src/platform/test/rom-test-main.c @@ -9,11 +9,17 @@ #include #include #include +#ifdef M_CORE_GBA #include +#endif +#ifdef M_CORE_GB +#include +#endif #include #include +#include #include #define ROM_TEST_OPTIONS "S:R:" @@ -48,6 +54,21 @@ void (*_armSwi16)(struct ARMCore* cpu, int immediate); void (*_armSwi32)(struct ARMCore* cpu, int immediate); #endif +#ifdef M_CORE_GB +enum GBReg { + GB_REG_A = 16, + GB_REG_F, + GB_REG_B, + GB_REG_C, + GB_REG_D, + GB_REG_E, + GB_REG_H, + GB_REG_L +}; + +static void _romTestGBCallback(void* context); +#endif + int main(int argc, char * argv[]) { signal(SIGINT, _romTestShutdown); @@ -82,17 +103,22 @@ int main(int argc, char * argv[]) { mCoreConfigSetDefaultValue(&core->config, "idleOptimization", "remove"); + bool cleanExit = false; + struct mCoreCallbacks callbacks = {0}; + callbacks.context = core; + switch (core->platform(core)) { #ifdef M_CORE_GBA - if (core->platform(core) == mPLATFORM_GBA) { + case mPLATFORM_GBA: ((struct GBA*) core->board)->hardCrash = false; + if (romTestOpts.returnCodeRegister >= 16) { + goto loadError; + } _exitSwiImmediate = romTestOpts.exitSwiImmediate; _returnCodeRegister = romTestOpts.returnCodeRegister; if (_exitSwiImmediate == 3) { // Hook into SWI 3 (shutdown) - struct mCoreCallbacks callbacks = {0}; - callbacks.context = core; callbacks.shutdown = _romTestSwi3Callback; core->addCoreCallbacks(core, &callbacks); } else { @@ -102,12 +128,25 @@ int main(int argc, char * argv[]) { _armSwi32 = ((struct GBA*) core->board)->cpu->irqh.swi32; ((struct GBA*) core->board)->cpu->irqh.swi32 = _romTestSwi32; } - } + break; #endif +#ifdef M_CORE_GB + case mPLATFORM_GB: + if (romTestOpts.returnCodeRegister < GB_REG_A) { + goto loadError; + } + + _returnCodeRegister = romTestOpts.returnCodeRegister; + + callbacks.shutdown = _romTestGBCallback; + core->addCoreCallbacks(core, &callbacks); + break; +#endif + default: + goto loadError; + } - bool cleanExit = true; if (!mCoreLoadFile(core, args.fname)) { - cleanExit = false; goto loadError; } if (args.patch) { @@ -142,6 +181,7 @@ int main(int argc, char * argv[]) { } while (!_dispatchExiting); core->unloadROM(core); + cleanExit = true; loadError: freeArguments(&args); @@ -182,6 +222,41 @@ static void _romTestSwi32(struct ARMCore* cpu, int immediate) { } #endif +#ifdef M_CORE_GB +static void _romTestGBCallback(void* context) { + struct mCore* core = context; + struct SM83Core* cpu = core->cpu; + + switch (_returnCodeRegister) { + case GB_REG_A: + _exitCode = cpu->a; + break; + case GB_REG_B: + _exitCode = cpu->b; + break; + case GB_REG_C: + _exitCode = cpu->c; + break; + case GB_REG_D: + _exitCode = cpu->d; + break; + case GB_REG_E: + _exitCode = cpu->e; + break; + case GB_REG_F: + _exitCode = cpu->f.packed; + break; + case GB_REG_H: + _exitCode = cpu->h; + break; + case GB_REG_L: + _exitCode = cpu->l; + break; + } + _dispatchExiting = true; +} +#endif + static bool _parseRomTestOpts(struct mSubParser* parser, int option, const char* arg) { struct RomTestOpts* opts = parser->opts; errno = 0; @@ -206,8 +281,63 @@ static bool _parseSwi(const char* swiStr, int* oSwi) { } static bool _parseNamedRegister(const char* regStr, unsigned int* oRegister) { - if (regStr[0] == 'r' || regStr[0] == 'R') { +#ifdef M_CORE_GB + static const enum GBReg gbMapping[] = { + ['a' - 'a'] = GB_REG_A, + ['b' - 'a'] = GB_REG_B, + ['c' - 'a'] = GB_REG_C, + ['d' - 'a'] = GB_REG_D, + ['e' - 'a'] = GB_REG_E, + ['f' - 'a'] = GB_REG_F, + ['h' - 'a'] = GB_REG_H, + ['l' - 'a'] = GB_REG_L, + }; +#endif + + switch (regStr[0]) { + case 'r': + case 'R': ++regStr; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; +#ifdef M_CORE_GB + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'h': + case 'l': + if (regStr[1] != '\0') { + return false; + } + *oRegister = gbMapping[regStr[0] - 'a']; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'H': + case 'L': + if (regStr[1] != '\0') { + return false; + } + *oRegister = gbMapping[regStr[0] - 'A']; + return true; +#endif } char* parseEnd;