diff --git a/src/libretro/core/core.hpp b/src/libretro/core/core.hpp index 418d4e6..eee08ef 100644 --- a/src/libretro/core/core.hpp +++ b/src/libretro/core/core.hpp @@ -93,6 +93,8 @@ namespace MelonDsDs { void WriteGbaSave(std::span savedata, uint32_t writeoffset, uint32_t writelen) noexcept; void WriteFirmware(const melonDS::Firmware& firmware, uint32_t writeoffset, uint32_t writelen) noexcept; bool UpdateOptionVisibility() noexcept; + + const melonDS::NDS* GetConsole() const noexcept { return Console.get(); } private: static constexpr auto REGEX_OPTIONS = std::regex_constants::ECMAScript | std::regex_constants::optimize; [[gnu::cold]] void ApplyConfig(const CoreConfig& config) noexcept; diff --git a/src/libretro/core/test.cpp b/src/libretro/core/test.cpp index adc7833..3eefe4d 100644 --- a/src/libretro/core/test.cpp +++ b/src/libretro/core/test.cpp @@ -18,8 +18,15 @@ #include +#include "core.hpp" #include "environment.hpp" +namespace MelonDsDs +{ + // sshhh...don't tell anyone + extern CoreState& Core; +} + extern "C" int libretropy_add_integers(int a, int b) { return a + b; } @@ -74,6 +81,38 @@ extern "C" const char* libretropy_get_save_directory() { return ok ? path : nullptr; } +extern "C" bool libretropy_get_power(retro_device_power* power) { + return retro::environment(RETRO_ENVIRONMENT_GET_DEVICE_POWER, power); +} + +extern "C" bool melondsds_console_exists() { + using namespace MelonDsDs; + const melonDS::NDS* console = Core.GetConsole(); + + return console != nullptr; +} + +extern "C" bool melondsds_arm7_bios_native() { + using namespace MelonDsDs; + const melonDS::NDS* console = Core.GetConsole(); + + return console ? console->IsLoadedARM7BIOSKnownNative() : false; +} + +extern "C" bool melondsds_arm9_bios_native() { + using namespace MelonDsDs; + const melonDS::NDS* console = Core.GetConsole(); + + return console ? console->IsLoadedARM7BIOSKnownNative() : false; +} + +extern "C" bool melondsds_firmware_native() { + using namespace MelonDsDs; + const melonDS::NDS* console = Core.GetConsole(); + + return console ? console->GetFirmware().GetHeader().Identifier != melonDS::GENERATED_FIRMWARE_IDENTIFIER : false; +} + extern "C" retro_proc_address_t MelonDsDs::GetRetroProcAddress(const char* sym) noexcept { if (string_is_equal(sym, "libretropy_add_integers")) return reinterpret_cast(libretropy_add_integers); @@ -102,6 +141,21 @@ extern "C" retro_proc_address_t MelonDsDs::GetRetroProcAddress(const char* sym) if (string_is_equal(sym, "libretropy_get_input_device_capabilities")) return reinterpret_cast(libretropy_get_input_device_capabilities); + if (string_is_equal(sym, "libretropy_get_power")) + return reinterpret_cast(libretropy_get_power); + + if (string_is_equal(sym, "melondsds_console_exists")) + return reinterpret_cast(melondsds_console_exists); + + if (string_is_equal(sym, "melondsds_arm7_bios_native")) + return reinterpret_cast(melondsds_arm7_bios_native); + + if (string_is_equal(sym, "melondsds_arm9_bios_native")) + return reinterpret_cast(melondsds_arm9_bios_native); + + if (string_is_equal(sym, "melondsds_firmware_native")) + return reinterpret_cast(melondsds_firmware_native); + return nullptr; } diff --git a/src/libretro/libretro.cpp b/src/libretro/libretro.cpp index 04d1db3..a81a452 100644 --- a/src/libretro/libretro.cpp +++ b/src/libretro/libretro.cpp @@ -62,7 +62,7 @@ using retro::task::TaskSpec; namespace MelonDsDs { // Aligned with CoreState to prevent undefined behavior alignas(CoreState) static std::array CoreStateBuffer; - static CoreState& Core = *reinterpret_cast(CoreStateBuffer.data()); + CoreState& Core = *reinterpret_cast(CoreStateBuffer.data()); } PUBLIC_SYMBOL void retro_init(void) { diff --git a/test/cmake/Booting.cmake b/test/cmake/Booting.cmake index 003b628..37d2f23 100644 --- a/test/cmake/Booting.cmake +++ b/test/cmake/Booting.cmake @@ -1,12 +1,12 @@ ## Direct Boot of NDS game #################################################### -add_retroarch_test( - NAME "Direct NDS boot with built-in system files succeeds" - CONTENT "${NDS_ROM}" - MAX_FRAMES 180 - CORE_OPTION "melonds_boot_mode=direct" - CORE_OPTION "melonds_console_mode=ds" - CORE_OPTION "melonds_sysfile_mode=builtin" +add_python_test( + NAME "Direct NDS boot with built-in system files succeeds" + TEST_MODULE basics.core_run_frames + CONTENT "${NDS_ROM}" + CORE_OPTION melonds_boot_mode=direct + CORE_OPTION melonds_console_mode=ds + CORE_OPTION melonds_sysfile_mode=builtin ) add_retroarch_test( diff --git a/test/cmake/Errors.cmake b/test/cmake/Errors.cmake index 204c715..4e0e6ab 100644 --- a/test/cmake/Errors.cmake +++ b/test/cmake/Errors.cmake @@ -1,43 +1,38 @@ -### With Content - -add_retroarch_test( - NAME "Core falls back to FreeBIOS if ARM7 BIOS is missing (NDS)" - CONTENT "${NDS_ROM}" - MAX_FRAMES 6 - CORE_OPTION "melonds_console_mode=ds" - CORE_OPTION "melonds_sysfile_mode=native" - CORE_OPTION "melonds_boot_mode=direct" - ARM9_BIOS - PASS_REGULAR_EXPRESSION "Falling back to FreeBIOS" +add_python_test( + NAME "Core falls back to FreeBIOS if ARM7 BIOS is missing (NDS)" + CONTENT "${NDS_ROM}" + TEST_MODULE errors.core_falls_back_to_freebios + CORE_OPTION melonds_console_mode=ds + CORE_OPTION melonds_sysfile_mode=native + CORE_OPTION melonds_boot_mode=direct + ARM9_BIOS ) -add_retroarch_test( - NAME "Core falls back to FreeBIOS if ARM9 BIOS is missing (NDS)" - CONTENT "${NDS_ROM}" - MAX_FRAMES 6 - CORE_OPTION "melonds_console_mode=ds" - CORE_OPTION "melonds_sysfile_mode=native" - CORE_OPTION "melonds_boot_mode=direct" - ARM7_BIOS - PASS_REGULAR_EXPRESSION "Falling back to FreeBIOS" +add_python_test( + NAME "Core falls back to FreeBIOS if ARM9 BIOS is missing (NDS)" + CONTENT "${NDS_ROM}" + TEST_MODULE errors.core_falls_back_to_freebios + CORE_OPTION melonds_console_mode=ds + CORE_OPTION melonds_sysfile_mode=native + CORE_OPTION melonds_boot_mode=direct + ARM7_BIOS ) -add_retroarch_test( - NAME "Core falls back to built-in firmware if native firmware is missing (NDS)" - CONTENT "${NDS_ROM}" - MAX_FRAMES 6 - CORE_OPTION "melonds_console_mode=ds" - CORE_OPTION "melonds_sysfile_mode=native" - CORE_OPTION "melonds_boot_mode=direct" - CORE_OPTION "melonds_firmware_nds_path=melonDS DS/${NDS_FIRMWARE_NAME}" - ARM7_BIOS - ARM9_BIOS - PASS_REGULAR_EXPRESSION "Falling back to built-in firmware" +add_python_test( + NAME "Core falls back to built-in firmware if native firmware is missing (NDS)" + CONTENT "${NDS_ROM}" + TEST_MODULE errors.core_falls_back_to_freebios + CORE_OPTION melonds_console_mode=ds + CORE_OPTION melonds_sysfile_mode=native + CORE_OPTION melonds_boot_mode=direct + CORE_OPTION "melonds_firmware_nds_path=melonDS DS/${NDS_FIRMWARE_NAME}" + ARM7_BIOS + ARM9_BIOS ) -add_emutest_test( - NAME "Loading invalid ROM does not cause a crash" - CONTENT "$" - TEST_SCRIPT "no-crash-on-invalid-rom.lua" - WILL_FAIL +add_python_test( + NAME "Loading invalid ROM does not cause a crash" + TEST_MODULE basics.core_loads_unloads_with_content + CONTENT "$" + WILL_FAIL ) diff --git a/test/python/errors/__init__.py b/test/python/errors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/python/errors/core_falls_back_to_freebios.py b/test/python/errors/core_falls_back_to_freebios.py new file mode 100644 index 0000000..a62c8d9 --- /dev/null +++ b/test/python/errors/core_falls_back_to_freebios.py @@ -0,0 +1,27 @@ +from ctypes import c_bool, CFUNCTYPE + +from libretro import Session + +import prelude + +session: Session +with prelude.session() as session: + proc_address_callback = session.proc_address_callback + assert proc_address_callback is not None + assert proc_address_callback.get_proc_address is not None + + console_exists = session.get_proc_address("melondsds_console_exists", CFUNCTYPE(c_bool)) + assert console_exists is not None + assert console_exists() + + arm7_native = session.get_proc_address("melondsds_arm7_bios_native", CFUNCTYPE(c_bool)) + assert arm7_native is not None + assert not arm7_native() + + arm9_native = session.get_proc_address("melondsds_arm9_bios_native", CFUNCTYPE(c_bool)) + assert arm9_native is not None + assert not arm9_native() + + firmware_native = session.get_proc_address("melondsds_firmware_native", CFUNCTYPE(c_bool)) + assert firmware_native is not None + assert not firmware_native()