diff --git a/.gitignore b/.gitignore index 76de8450c..999fdd673 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,15 @@ +# Generic files *.user* *~ *.swp *.pyc +# Build directories /build /build-* /.vs +# Build files *.a *.dylib *.dll @@ -18,5 +21,9 @@ CMakeCache.txt CMakeFiles CMakeSettings.json cmake_install.cmake +hle-bios.bin version.c -*.d + +# Runtime generated cruft +*.sav +*.ss0 diff --git a/CHANGES b/CHANGES index 3829d23fa..d850f2002 100644 --- a/CHANGES +++ b/CHANGES @@ -1,12 +1,103 @@ 0.11.0: (Future) Features: + - Scripting: New `input` API for getting raw keyboard/mouse/controller state + - Scripting: New `storage` API for saving data for a script, e.g. settings + - Scripting: Debugger integration to allow for breakpoints and watchpoints - New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81 - Debugger: Add range watchpoints Emulation fixes: + - GB I/O: Fix STAT writing IRQ trigger conditions (fixes mgba.io/i/2501) + - GB Serialize: Add missing Pocket Cam state to savestates + - GB Video: Implement DMG-style sprite ordering + - GBA: Unhandled bkpt should be treated as an undefined exception + - GBA GPIO: Fix tilt scale and orientation (fixes mgba.io/i/2703) + - GBA I/O: Fix HALTCNT access behavior (fixes mgba.io/i/2309) + - GBA SIO: Fix MULTI mode SIOCNT bit 7 writes on secondary GBAs (fixes mgba.io/i/3110) - GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722) +Other fixes: + - Core: Fix inconsistencies with setting game-specific overrides (fixes mgba.io/i/2963) + - Debugger: Fix writing to specific segment in command-line debugger + - GB: Fix uninitialized save data when loading undersized temporary saves + - Qt: Fix savestate preview sizes with different scales (fixes mgba.io/i/2560) + - Updater: Fix updating appimage across filesystems Misc: + - Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826) + - GB: Prevent incompatible BIOSes from being used on differing models - GB Serialize: Add missing savestate support for MBC6 and NT (newer) - GBA: Improve detection of valid ELF ROMs + - mGUI: Enable auto-softpatching (closes mgba.io/i/2899) + - mGUI: Persist fast forwarding after closing menu (fixes mgba.io/i/2414) + - Qt: Handle multiple save game files for disparate games separately (fixes mgba.io/i/2887) + - Qt: Remove maligned double-click-to-fullscreen shortcut (closes mgba.io/i/2632) + - Qt: Pass logging context through to video proxy thread (fixes mgba.io/i/3095) + - Scripting: Add `callbacks:oneshot` for single-call callbacks + - Switch: Add bilinear filtering option (closes mgba.io/i/3111) + - Vita: Add imc0 and xmc0 mount point support + +0.10.3: (2024-01-07) +Emulation fixes: + - ARM: Remove obsolete force-alignment in `bx pc` (fixes mgba.io/i/2964) + - ARM: Fake bpkt instruction should take no cycles (fixes mgba.io/i/2551) + - GB Audio: Fix channels 1/2 staying muted if restarted after long silence + - GB Audio: Fix channel 1 restarting if sweep applies after stop (fixes mgba.io/i/2965) + - GB Audio: Fix restarting envelope when writing to register (fixes mgba.io/i/3067) + - GB Audio: Improve "zombie mode" emulation in CGB mode (fixes mgba.io/i/2029) + - GB I/O: Read back proper SVBK value after writing 0 (fixes mgba.io/i/2921) + - GB SIO: Disabling SIO should cancel pending transfers (fixes mgba.io/i/2537) + - GBA Audio: Fix sample timing drifting when changing sample interval + - GBA Audio: Fix initial channel 3 wave RAM (fixes mgba.io/i/2947) + - GBA Audio: Fix sample position issues when rate changes (fixes mgba.io/i/3006) + - GBA GPIO: Fix tilt scale and orientation (fixes mgba.io/i/2703) + - GBA BIOS: Fix clobbering registers with word-sized CpuSet + - GBA SIO: Fix normal mode SI/SO semantics (fixes mgba.io/i/2925) +Other fixes: + - GB: Fix applying a patch that changes the cartridge mapper (fixes mgba.io/i/3077) + - GBA Savedata: Fix crash when resizing flash save games for RTC data + - mGUI: Fix cases where an older save state screenshot would be shown (fixes mgba.io/i/2183) + - Qt: Re-enable sync for multiplayer windows that aren't connected (fixes mgba.io/i/2974) + - Qt: Fix mute settings not being loaded on setting screen (fixes mgba.io/i/2990) + - Qt: Fix screen freezing on macOS after closing save state window (fixes mgba.io/i/2885) + - Vita: Fix camera setting not appearing (fixes mgba.io/i/3012) +Misc: + - mGUI: Persist fast forwarding after closing menu (fixes mgba.io/i/2414) + - Qt: Add exporting of SAV + RTC saves from Save Converter to strip RTC data + - VFS: Use anonymousMemoryMap for large 7z allocations (fixes mgba.io/i/3013) + +0.10.2: (2023-04-23) +Emulation fixes: + - GBA Audio: Fix improperly deserializing GB audio registers (fixes mgba.io/i/2793) + - GBA Audio: Clear GB audio state when disabled + - GBA Memory: Make VRAM access stalls only apply to BG RAM + - GBA Overrides: Fix saving in PMD:RRT (JP) (fixes mgba.io/i/2862) + - GBA SIO: Fix SIOCNT SI pin value after attaching player 2 (fixes mgba.io/i/2805) + - GBA SIO: Fix unconnected normal mode SIOCNT SI bit (fixes mgba.io/i/2810) + - GBA SIO: Normal mode transfers with no clock should not finish (fixes mgba.io/i/2811) + - GBA Timers: Cascading timers don't tick when disabled (fixes mgba.io/i/2812) + - GBA Video: Fix interpolation issues with OpenGL renderer +Other fixes: + - Core: Allow sending thread requests to a crashed core (fixes mgba.io/i/2784) + - FFmpeg: Force lower sample rate for codecs not supporting high rates (fixes mgba.io/i/2869) + - Qt: Fix crash when attempting to use OpenGL 2.1 to 3.1 (fixes mgba.io/i/2794) + - Qt: Disable sync while running scripts from main thread (fixes mgba.io/i/2738) + - Qt: Properly cap number of attached players by platform (fixes mgba.io/i/2807) + - Qt: Disable attempted linking betwen incompatible platforms (fixes mgba.io/i/2702) + - Qt: Fix modifier key names in shortcut editor (fixes mgba.io/i/2817) + - Qt: Fix a handful of edge cases with graphics viewers (fixes mgba.io/i/2827) + - Qt: Fix full-buffer rewind + - Qt: Fix crash if loading a shader fails + - Qt: Fix black screen when starting with a game (fixes mgba.io/i/2781) + - Qt: Fix OSD on modern macOS (fixes mgba.io/i/2736) + - Qt: Fix checked state of mute menu option at load (fixes mgba.io/i/2701) + - Qt: Remove OpenGL proxy thread and override SwapInterval directly instead + - Scripting: Fix receiving packets for client sockets + - Scripting: Fix empty receive calls returning unknown error on Windows + - Scripting: Return proper callback ID from socket.add + - Vita: Work around broken mktime implementation in Vita SDK (fixes mgba.io/i/2876) +Misc: + - Qt: Include wayland QPA in AppImage (fixes mgba.io/i/2796) + - Qt: Stop eating boolean action key events (fixes mgba.io/i/2636) + - Qt: Automatically change video file extension as appropriate + - Qt: Swap P1 and other player's save if P1 loaded it first (closes mgba.io/i/2750) 0.10.1: (2023-01-10) Emulation fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 42cff1ebc..a1e730e04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.3) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/src/platform/cmake/") if(POLICY CMP0025) @@ -34,8 +34,12 @@ if(NOT MSVC) # mingw32 likes to complain about using the "wrong" format strings despite them actually working set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-format") endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=implicit-function-declaration -Werror=implicit-int") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=implicit-function-declaration -Werror=implicit-int -fwrapv") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + # TODO: Remove this once mScript KV pairs support const correctness + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=incompatible-pointer-types") + endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS} -Woverloaded-virtual") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267 /Zc:preprocessor-") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146 /wd4267 /Zc:preprocessor-") @@ -55,6 +59,7 @@ if(NOT LIBMGBA_ONLY) set(USE_SQLITE3 ON CACHE BOOL "Whether or not to enable SQLite3 support") set(USE_ELF ON CACHE BOOL "Whether or not to enable ELF support") set(USE_LUA ON CACHE BOOL "Whether or not to enable Lua scripting support") + set(USE_JSON_C ON CACHE BOOL "Whether or not to enable JSON-C support") set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core") set(M_CORE_GB ON CACHE BOOL "Build Game Boy core") set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support") @@ -80,6 +85,7 @@ if(NOT LIBMGBA_ONLY) set(BUILD_GLES2 ON CACHE BOOL "Build with OpenGL|ES 2") set(BUILD_GLES3 ON CACHE BOOL "Build with OpenGL|ES 3") set(BUILD_DOCGEN OFF CACHE BOOL "Build the scripting API documentation generator") + set(BUILD_MAINTAINER_TOOLS OFF CACHE BOOL "Build tools only useful for maintainers") set(USE_EPOXY ON CACHE STRING "Build with libepoxy") set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies") set(DISTBUILD OFF CACHE BOOL "Build distribution packages") @@ -88,6 +94,7 @@ if(NOT LIBMGBA_ONLY) mark_as_advanced(WIN32_UNIX_PATHS) endif() mark_as_advanced(BUILD_DOCGEN) + mark_as_advanced(BUILD_MAINTAINER_TOOLS) else() set(DISABLE_FRONTENDS ON) set(DISABLE_DEPS ON) @@ -175,7 +182,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/version.c.in ${CMAKE_CURRENT source_group("Generated sources" FILES ${CMAKE_CURRENT_BINARY_DIR}/version.c) # Advanced settings -if(NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_COMPILER_VERSION VERSION_LESS "4.5")) +if(NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.5")) set(DEFAULT_LTO ON) else() set(DEFAULT_LTO OFF) @@ -337,6 +344,8 @@ find_function(popcount32) find_function(futimens) find_function(futimes) +find_function(realpath) + if(ANDROID AND ANDROID_NDK_MAJOR GREATER 13) find_function(localtime_r) set(HAVE_STRTOF_L ON) @@ -419,6 +428,13 @@ if(BUILD_GL) elseif(UNIX AND NOT APPLE AND TARGET OpenGL::GL) set(OPENGL_LIBRARY OpenGL::GL) endif() + if(OpenGL_GLX_FOUND) + list(APPEND FEATURES GLX) + endif() + if(OpenGL_EGL_FOUND) + list(APPEND FEATURES EGL) + list(APPEND OPENGL_LIBRARY ${OPENGL_egl_LIBRARY}) + endif() endif() if(BUILD_GL) list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c) @@ -477,6 +493,7 @@ endif() if(DISABLE_DEPS) set(USE_GDB_STUB OFF) set(USE_DISCORD_RPC OFF) + set(USE_JSON_C OFF) set(USE_SQLITE3 OFF) set(USE_PNG OFF) set(USE_ZLIB OFF) @@ -522,14 +539,12 @@ if(USE_EDITLINE) set(DEBUGGER_LIB ${LIBEDIT_LIBRARIES}) endif() set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libedit2") - list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/editline/cli-el-backend.c") else() set(DEBUGGER_LIB "") endif() if(USE_GDB_STUB) list(APPEND FEATURES GDB_STUB) - list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/debugger/gdb-stub.c) endif() source_group("Debugger" FILES ${DEBUGGER_SRC}) @@ -765,11 +780,36 @@ endif() if(ENABLE_SCRIPTING) list(APPEND ENABLES SCRIPTING) + find_feature(USE_JSON_C "json-c") if(NOT USE_LUA VERSION_LESS 5.1) find_feature(USE_LUA "Lua" ${USE_LUA}) else() find_feature(USE_LUA "Lua") endif() + if(USE_JSON_C) + list(APPEND FEATURES JSON_C) + if(TARGET json-c::json-c) + list(APPEND DEPENDENCY_LIB json-c::json-c) + get_target_property(JSON_C_SONAME json-c::json-c IMPORTED_SONAME_NONE) + string(SUBSTRING "${JSON_C_SONAME}" 13 -1 JSON_C_SOVER) + + # This is only needed on 0.15, but the target unhelpfully does not contain version info + get_target_property(JSON_C_INCLUDE_DIR json-c::json-c INTERFACE_INCLUDE_DIRECTORIES) + if(NOT JSON_C_INCLUDE_DIR MATCHES json-c$) + include_directories(AFTER "${JSON_C_INCLUDE_DIR}/json-c") + endif() + else() + if(${json-c_VERSION} VERSION_LESS 0.13.0) + set(JSON_C_SOVER 3) + elseif(${json-c_VERSION} VERSION_LESS 0.15.0) + set(JSON_C_SOVER 4) + endif() + list(APPEND DEPENDENCY_LIB ${json-c_LIBRARIES}) + include_directories(AFTER ${json-c_INCLUDE_DIRS}) + link_directories(${json-c_LIBDIRS}) + endif() + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libjson-c${JSON_C_SOVER}") + endif() if(USE_LUA) list(APPEND FEATURE_DEFINES USE_LUA) include_directories(AFTER ${LUA_INCLUDE_DIR}) @@ -989,7 +1029,7 @@ if(BUILD_UPDATER) add_executable(updater-stub WIN32 ${CORE_VFS_SRC} ${VFS_SRC} ${OS_SRC} ${UTIL_BASE_SRC} ${THIRD_PARTY_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/src/core/config.c ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/updater.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/feature/updater-main.c) + ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/updater-main.c) target_link_libraries(updater-stub ${ZLIB_LIBRARY} ${ZLIB_LIBRARY} ${ZIP_LIBRARIES} ${OS_LIB} ${PLATFORM_LIBRARY}) set_target_properties(updater-stub PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FUNCTION_DEFINES};${FEATURE_DEFINES};BUILD_STATIC") if(MSVC) @@ -1001,10 +1041,15 @@ if(BUILD_UPDATER) endif() if(ENABLE_SCRIPTING AND BUILD_DOCGEN) - add_executable(docgen ${CMAKE_CURRENT_SOURCE_DIR}/src/script/docgen.c) + add_executable(docgen ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/docgen.c) target_link_libraries(docgen ${OS_LIB} ${PLATFORM_LIBRARY} ${BINARY_NAME}) endif() +if(BUILD_MAINTAINER_TOOLS) + add_executable(font-sdf-tool ${CMAKE_CURRENT_SOURCE_DIR}/src/tools/font-sdf.c ${CMAKE_CURRENT_SOURCE_DIR}/src/util/gui/font-metrics.c) + target_link_libraries(font-sdf-tool ${OS_LIB} ${PLATFORM_LIBRARY} ${BINARY_NAME}) +endif() + if(BUILD_SDL) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/sdl ${CMAKE_CURRENT_BINARY_DIR}/sdl) endif() @@ -1289,6 +1334,7 @@ if(NOT QUIET AND NOT LIBMGBA_ONLY) else() message(STATUS " Lua: ${USE_LUA}") endif() + message(STATUS " storage API: ${USE_JSON_C}") endif() message(STATUS "Frontends:") message(STATUS " Qt: ${BUILD_QT}") diff --git a/README.md b/README.md index 20507604e..78b69f255 100644 --- a/README.md +++ b/README.md @@ -125,9 +125,9 @@ Compiling requires using CMake 3.1 or newer. GCC, Clang, and Visual Studio 2019 #### Docker building -The recommended way to build for most platforms is to use Docker. Several Docker images are provided that contain the requisite toolchain and dependencies for building mGBA across several platforms. +The recommended way to build for most platforms is to use Docker. Several Docker images are provided that contain the requisite toolchain and dependencies for building mGBA across several platforms. -Note: If you are on an older Windows system before Windows 10, you may need to configure your Docker to use VirtualBox shared folders to correctly map your current `mgba` checkout directory to the Docker image's working directory. (See issue [#1985](https://mgba.io/i/1985) for details.) +Note: If you are on an older Windows system before Windows 10, you may need to configure your Docker to use VirtualBox shared folders to correctly map your current `mgba` checkout directory to the Docker image's working directory. (See issue [#1985](https://mgba.io/i/1985) for details.) To use a Docker image to build mGBA, simply run the following command while in the root of an mGBA checkout: @@ -234,6 +234,7 @@ mGBA has no hard dependencies, however, the following optional dependencies are - SQLite3: for game databases. - libelf: for ELF loading. - Lua: for scripting. +- json-c: for the scripting `storage` API. SQLite3, libpng, and zlib are included with the emulator, so they do not need to be externally compiled first. @@ -254,7 +255,7 @@ Footnotes Copyright --------- -mGBA is Copyright © 2013 – 2022 Jeffrey Pfau. It is distributed under the [Mozilla Public License version 2.0](https://www.mozilla.org/MPL/2.0/). A copy of the license is available in the distributed LICENSE file. +mGBA is Copyright © 2013 – 2023 Jeffrey Pfau. It is distributed under the [Mozilla Public License version 2.0](https://www.mozilla.org/MPL/2.0/). A copy of the license is available in the distributed LICENSE file. mGBA contains the following third-party libraries: diff --git a/cinema/gb/acid/cgb-acid2/baseline_0000.png b/cinema/gb/acid/cgb-acid2/baseline_0000.png new file mode 100644 index 000000000..4baff3425 Binary files /dev/null and b/cinema/gb/acid/cgb-acid2/baseline_0000.png differ diff --git a/cinema/gb/acid/cgb-acid2/test.gbc b/cinema/gb/acid/cgb-acid2/test.gbc new file mode 100644 index 000000000..5f71bd360 Binary files /dev/null and b/cinema/gb/acid/cgb-acid2/test.gbc differ diff --git a/cinema/gb/acid/config.ini b/cinema/gb/acid/config.ini new file mode 100644 index 000000000..e6b9f2af6 --- /dev/null +++ b/cinema/gb/acid/config.ini @@ -0,0 +1,6 @@ +[testinfo] +skip=15 +frames=1 + +[ports.cinema] +sgb.borders=0 diff --git a/cinema/gb/acid/dmg-acid2/baseline_0000.png b/cinema/gb/acid/dmg-acid2/baseline_0000.png new file mode 100644 index 000000000..fde56ebc3 Binary files /dev/null and b/cinema/gb/acid/dmg-acid2/baseline_0000.png differ diff --git a/cinema/gb/acid/dmg-acid2/test.gb b/cinema/gb/acid/dmg-acid2/test.gb new file mode 100644 index 000000000..a25ef9485 Binary files /dev/null and b/cinema/gb/acid/dmg-acid2/test.gb differ diff --git a/cinema/gb/mooneye-gb/manual-only/sprite_priority/baseline_0000.png b/cinema/gb/mooneye-gb/manual-only/sprite_priority/baseline_0000.png index 64aac5965..cb3569baf 100644 Binary files a/cinema/gb/mooneye-gb/manual-only/sprite_priority/baseline_0000.png and b/cinema/gb/mooneye-gb/manual-only/sprite_priority/baseline_0000.png differ diff --git a/cinema/gb/mooneye-gb/manual-only/sprite_priority/xbaseline_0000.png b/cinema/gb/mooneye-gb/manual-only/sprite_priority/xbaseline_0000.png deleted file mode 100644 index 2201a6ac5..000000000 Binary files a/cinema/gb/mooneye-gb/manual-only/sprite_priority/xbaseline_0000.png and /dev/null differ diff --git a/cinema/gb/mooneye-gb/misc/boot_div-cgb0/xbaseline_0000.png b/cinema/gb/mooneye-gb/misc/boot_div-cgb0/xbaseline_0000.png index b9d24cc3a..767dc72dd 100644 Binary files a/cinema/gb/mooneye-gb/misc/boot_div-cgb0/xbaseline_0000.png and b/cinema/gb/mooneye-gb/misc/boot_div-cgb0/xbaseline_0000.png differ diff --git a/cinema/gb/mooneye-gb/manual-only/sprite_priority/config.ini b/cinema/gb/samesuite/apu/channel_1/align/config.ini similarity index 100% rename from cinema/gb/mooneye-gb/manual-only/sprite_priority/config.ini rename to cinema/gb/samesuite/apu/channel_1/align/config.ini diff --git a/cinema/gb/samesuite/apu/channel_1/align/test.gb b/cinema/gb/samesuite/apu/channel_1/align/test.gb new file mode 100644 index 000000000..2d3b6c8b1 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/align/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/align/test.sym b/cinema/gb/samesuite/apu/channel_1/align/test.sym new file mode 100644 index 000000000..c2dc87faf --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/align/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:0b92 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/align/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/align/xbaseline_0000.png new file mode 100644 index 000000000..10bf03557 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/align/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/align_cpu/config.ini b/cinema/gb/samesuite/apu/channel_1/align_cpu/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/align_cpu/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/align_cpu/test.gb b/cinema/gb/samesuite/apu/channel_1/align_cpu/test.gb new file mode 100644 index 000000000..b5fe60418 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/align_cpu/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/align_cpu/test.sym b/cinema/gb/samesuite/apu/channel_1/align_cpu/test.sym new file mode 100644 index 000000000..c2dc87faf --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/align_cpu/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:0b92 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/align_cpu/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/align_cpu/xbaseline_0000.png new file mode 100644 index 000000000..091b2f2d2 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/align_cpu/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/delay/config.ini b/cinema/gb/samesuite/apu/channel_1/delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/delay/test.gb b/cinema/gb/samesuite/apu/channel_1/delay/test.gb new file mode 100644 index 000000000..68f46f118 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/delay/test.sym b/cinema/gb/samesuite/apu/channel_1/delay/test.sym new file mode 100644 index 000000000..9d3c63f11 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:09ed StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/delay/xbaseline_0000.png new file mode 100644 index 000000000..f42030316 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/duty/config.ini b/cinema/gb/samesuite/apu/channel_1/duty/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/duty/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/duty/test.gb b/cinema/gb/samesuite/apu/channel_1/duty/test.gb new file mode 100644 index 000000000..2ffcd2b6e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/duty/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/duty/test.sym b/cinema/gb/samesuite/apu/channel_1/duty/test.sym new file mode 100644 index 000000000..8086ebfcc --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/duty/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0649 TestGroup +00:0a39 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/duty/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/duty/xbaseline_0000.png new file mode 100644 index 000000000..915645259 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/duty/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/duty_delay/config.ini b/cinema/gb/samesuite/apu/channel_1/duty_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/duty_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/duty_delay/test.gb b/cinema/gb/samesuite/apu/channel_1/duty_delay/test.gb new file mode 100644 index 000000000..c31b55e3b Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/duty_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/duty_delay/test.sym b/cinema/gb/samesuite/apu/channel_1/duty_delay/test.sym new file mode 100644 index 000000000..b29c8ca51 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/duty_delay/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0639 TestGroup +00:0ec9 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/duty_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/duty_delay/xbaseline_0000.png new file mode 100644 index 000000000..1ce7f7009 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/duty_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/config.ini b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/test.gb b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/test.gb new file mode 100644 index 000000000..ae71d4fa5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/test.sym b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/test.sym new file mode 100644 index 000000000..947b9e80d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05c3 RunTest +00:091d StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/xbaseline_0000.png new file mode 100644 index 000000000..da02bff6c Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/extra_length_clocking-cgb0B/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change/config.ini b/cinema/gb/samesuite/apu/channel_1/freq_change/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change/test.gb b/cinema/gb/samesuite/apu/channel_1/freq_change/test.gb new file mode 100644 index 000000000..7cc20d0df Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change/test.sym b/cinema/gb/samesuite/apu/channel_1/freq_change/test.sym new file mode 100644 index 000000000..642158c69 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0639 TestGroup +00:0ed6 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/freq_change/xbaseline_0000.png new file mode 100644 index 000000000..03e8af34a Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/config.ini b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/test.gb b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/test.gb new file mode 100644 index 000000000..674567b25 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/test.sym b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/test.sym new file mode 100644 index 000000000..41a009237 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:0875 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/xbaseline_0000.png new file mode 100644 index 000000000..c15aafeff Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-A/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/config.ini b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/test.gb b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/test.gb new file mode 100644 index 000000000..7cc87d6d3 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/test.sym b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/test.sym new file mode 100644 index 000000000..41a009237 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:0875 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/xbaseline_0000.png new file mode 100644 index 000000000..37d552ff9 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgb0BC/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/config.ini b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/test.gb b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/test.gb new file mode 100644 index 000000000..c456cc12c Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/test.sym b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/test.sym new file mode 100644 index 000000000..41a009237 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:0875 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/xbaseline_0000.png new file mode 100644 index 000000000..c15aafeff Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/freq_change_timing-cgbDE/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/config.ini b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/test.gb b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/test.gb new file mode 100644 index 000000000..19fbbd625 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/test.sym b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/test.sym new file mode 100644 index 000000000..ba31606e6 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:088f StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/xbaseline_0000.png new file mode 100644 index 000000000..24c22936b Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/nrx2_glitch/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/config.ini b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/config.ini new file mode 100644 index 000000000..5c2a99de9 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/config.ini @@ -0,0 +1,3 @@ +[testinfo] +fail=1 +skip=180 diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/test.gb b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/test.gb new file mode 100644 index 000000000..a628e4dfc Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/test.sym b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/test.sym new file mode 100644 index 000000000..db14b866d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05f3 RunTest +00:1a0f StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/xbaseline_0000.png new file mode 100644 index 000000000..0032b919f Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/nrx2_speed_change/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/restart/config.ini b/cinema/gb/samesuite/apu/channel_1/restart/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/restart/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/restart/test.gb b/cinema/gb/samesuite/apu/channel_1/restart/test.gb new file mode 100644 index 000000000..c6924dd22 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/restart/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/restart/test.sym b/cinema/gb/samesuite/apu/channel_1/restart/test.sym new file mode 100644 index 000000000..b02f7d89d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/restart/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:1a82 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/restart/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/restart/xbaseline_0000.png new file mode 100644 index 000000000..7d68bb0cd Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/restart/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/config.ini b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/test.gb b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/test.gb new file mode 100644 index 000000000..ed3cee586 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/test.sym b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/test.sym new file mode 100644 index 000000000..ad1017c62 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:085e StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/xbaseline_0000.png new file mode 100644 index 000000000..69fb020dd Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/restart_nrx2_glitch/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/stop_div/config.ini b/cinema/gb/samesuite/apu/channel_1/stop_div/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/stop_div/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/stop_div/test.gb b/cinema/gb/samesuite/apu/channel_1/stop_div/test.gb new file mode 100644 index 000000000..d6167bf40 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/stop_div/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/stop_div/test.sym b/cinema/gb/samesuite/apu/channel_1/stop_div/test.sym new file mode 100644 index 000000000..ccb41512d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/stop_div/test.sym @@ -0,0 +1,46 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05e3 RunTest +00:05f9 TestGroup +00:0801 ShortTestGroup +00:0912 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/stop_div/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/stop_div/xbaseline_0000.png new file mode 100644 index 000000000..aa1e6dc91 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/stop_div/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/stop_restart/config.ini b/cinema/gb/samesuite/apu/channel_1/stop_restart/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/stop_restart/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/stop_restart/test.gb b/cinema/gb/samesuite/apu/channel_1/stop_restart/test.gb new file mode 100644 index 000000000..3c666629d Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/stop_restart/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/stop_restart/test.sym b/cinema/gb/samesuite/apu/channel_1/stop_restart/test.sym new file mode 100644 index 000000000..dcdf4b403 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/stop_restart/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:1f92 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/stop_restart/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/stop_restart/xbaseline_0000.png new file mode 100644 index 000000000..454b9dc1e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/stop_restart/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/sweep/config.ini b/cinema/gb/samesuite/apu/channel_1/sweep/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/sweep/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/sweep/test.gb b/cinema/gb/samesuite/apu/channel_1/sweep/test.gb new file mode 100644 index 000000000..02308c0c2 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/sweep/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/sweep/test.sym b/cinema/gb/samesuite/apu/channel_1/sweep/test.sym new file mode 100644 index 000000000..f9664ac54 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/sweep/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:1cce StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/sweep/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/sweep/xbaseline_0000.png new file mode 100644 index 000000000..dde05538e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/sweep/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart/config.ini b/cinema/gb/samesuite/apu/channel_1/sweep_restart/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/sweep_restart/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart/test.gb b/cinema/gb/samesuite/apu/channel_1/sweep_restart/test.gb new file mode 100644 index 000000000..61812c099 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/sweep_restart/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart/test.sym b/cinema/gb/samesuite/apu/channel_1/sweep_restart/test.sym new file mode 100644 index 000000000..28c7f230e --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/sweep_restart/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:0940 RunTest.round_6 +00:1545 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/sweep_restart/xbaseline_0000.png new file mode 100644 index 000000000..daac7431a Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/sweep_restart/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/config.ini b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/test.gb b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/test.gb new file mode 100644 index 000000000..848286fe7 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/test.sym b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/test.sym new file mode 100644 index 000000000..c3a4f1938 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1e2a StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/xbaseline_0000.png new file mode 100644 index 000000000..f4485a7d7 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/sweep_restart_2/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/volume/config.ini b/cinema/gb/samesuite/apu/channel_1/volume/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/volume/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_1/volume/test.gb b/cinema/gb/samesuite/apu/channel_1/volume/test.gb new file mode 100644 index 000000000..a5f1b1516 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/volume/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/volume/test.sym b/cinema/gb/samesuite/apu/channel_1/volume/test.sym new file mode 100644 index 000000000..a1d34fe55 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/volume/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0643 SubTestGroup +00:0ac4 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/volume/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/volume/xbaseline_0000.png new file mode 100644 index 000000000..e639befda Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/volume/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_1/volume_div/config.ini b/cinema/gb/samesuite/apu/channel_1/volume_div/config.ini new file mode 100644 index 000000000..26f3fb74a --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/volume_div/config.ini @@ -0,0 +1,3 @@ +[testinfo] +fail=1 +skip=120 diff --git a/cinema/gb/samesuite/apu/channel_1/volume_div/test.gb b/cinema/gb/samesuite/apu/channel_1/volume_div/test.gb new file mode 100644 index 000000000..bf03c8346 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/volume_div/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_1/volume_div/test.sym b/cinema/gb/samesuite/apu/channel_1/volume_div/test.sym new file mode 100644 index 000000000..36b01a6dc --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_1/volume_div/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05eb RunTest +00:05fb TestGroup +00:0a7c StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_1/volume_div/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_1/volume_div/xbaseline_0000.png new file mode 100644 index 000000000..93f9b150a Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_1/volume_div/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/align/config.ini b/cinema/gb/samesuite/apu/channel_2/align/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/align/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/align/test.gb b/cinema/gb/samesuite/apu/channel_2/align/test.gb new file mode 100644 index 000000000..7cdcd4840 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/align/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/align/test.sym b/cinema/gb/samesuite/apu/channel_2/align/test.sym new file mode 100644 index 000000000..c2dc87faf --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/align/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:0b92 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/align/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/align/xbaseline_0000.png new file mode 100644 index 000000000..c7a3758e7 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/align/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/align_cpu/config.ini b/cinema/gb/samesuite/apu/channel_2/align_cpu/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/align_cpu/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/align_cpu/test.gb b/cinema/gb/samesuite/apu/channel_2/align_cpu/test.gb new file mode 100644 index 000000000..b4d8b644a Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/align_cpu/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/align_cpu/test.sym b/cinema/gb/samesuite/apu/channel_2/align_cpu/test.sym new file mode 100644 index 000000000..c2dc87faf --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/align_cpu/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:0b92 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/align_cpu/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/align_cpu/xbaseline_0000.png new file mode 100644 index 000000000..5b3549917 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/align_cpu/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/delay/config.ini b/cinema/gb/samesuite/apu/channel_2/delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/delay/test.gb b/cinema/gb/samesuite/apu/channel_2/delay/test.gb new file mode 100644 index 000000000..0fa95c101 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/delay/test.sym b/cinema/gb/samesuite/apu/channel_2/delay/test.sym new file mode 100644 index 000000000..9d3c63f11 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:09ed StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/delay/xbaseline_0000.png new file mode 100644 index 000000000..f4ab7b2dc Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/duty/config.ini b/cinema/gb/samesuite/apu/channel_2/duty/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/duty/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/duty/test.gb b/cinema/gb/samesuite/apu/channel_2/duty/test.gb new file mode 100644 index 000000000..4d8275548 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/duty/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/duty/test.sym b/cinema/gb/samesuite/apu/channel_2/duty/test.sym new file mode 100644 index 000000000..8086ebfcc --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/duty/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0649 TestGroup +00:0a39 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/duty/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/duty/xbaseline_0000.png new file mode 100644 index 000000000..6a9c96269 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/duty/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/duty_delay/config.ini b/cinema/gb/samesuite/apu/channel_2/duty_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/duty_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/duty_delay/test.gb b/cinema/gb/samesuite/apu/channel_2/duty_delay/test.gb new file mode 100644 index 000000000..a3df171e0 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/duty_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/duty_delay/test.sym b/cinema/gb/samesuite/apu/channel_2/duty_delay/test.sym new file mode 100644 index 000000000..b29c8ca51 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/duty_delay/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0639 TestGroup +00:0ec9 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/duty_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/duty_delay/xbaseline_0000.png new file mode 100644 index 000000000..2bcbf07e1 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/duty_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/config.ini b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/test.gb b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/test.gb new file mode 100644 index 000000000..fba679c8d Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/test.sym b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/test.sym new file mode 100644 index 000000000..947b9e80d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05c3 RunTest +00:091d StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/xbaseline_0000.png new file mode 100644 index 000000000..3221aa805 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/extra_length_clocking-cgb0B/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/freq_change/config.ini b/cinema/gb/samesuite/apu/channel_2/freq_change/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/freq_change/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/freq_change/test.gb b/cinema/gb/samesuite/apu/channel_2/freq_change/test.gb new file mode 100644 index 000000000..1951af03d Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/freq_change/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/freq_change/test.sym b/cinema/gb/samesuite/apu/channel_2/freq_change/test.sym new file mode 100644 index 000000000..642158c69 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/freq_change/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:0639 TestGroup +00:0ed6 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/freq_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/freq_change/xbaseline_0000.png new file mode 100644 index 000000000..ed3726007 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/freq_change/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/config.ini b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/test.gb b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/test.gb new file mode 100644 index 000000000..5db3a126e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/test.sym b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/test.sym new file mode 100644 index 000000000..ba31606e6 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:088f StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/xbaseline_0000.png new file mode 100644 index 000000000..eefe570bd Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/nrx2_glitch/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/config.ini b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/config.ini new file mode 100644 index 000000000..5c2a99de9 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/config.ini @@ -0,0 +1,3 @@ +[testinfo] +fail=1 +skip=180 diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/test.gb b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/test.gb new file mode 100644 index 000000000..06ba9b13c Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/test.sym b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/test.sym new file mode 100644 index 000000000..db14b866d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05f3 RunTest +00:1a0f StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/xbaseline_0000.png new file mode 100644 index 000000000..2804b6f3a Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/nrx2_speed_change/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/restart/config.ini b/cinema/gb/samesuite/apu/channel_2/restart/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/restart/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/restart/test.gb b/cinema/gb/samesuite/apu/channel_2/restart/test.gb new file mode 100644 index 000000000..147398aeb Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/restart/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/restart/test.sym b/cinema/gb/samesuite/apu/channel_2/restart/test.sym new file mode 100644 index 000000000..b02f7d89d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/restart/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:1a82 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/restart/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/restart/xbaseline_0000.png new file mode 100644 index 000000000..23b8dcf15 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/restart/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/config.ini b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/test.gb b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/test.gb new file mode 100644 index 000000000..734c80b57 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/test.sym b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/test.sym new file mode 100644 index 000000000..ad1017c62 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:085e StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/xbaseline_0000.png new file mode 100644 index 000000000..21dfc5ad6 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/restart_nrx2_glitch/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/stop_div/config.ini b/cinema/gb/samesuite/apu/channel_2/stop_div/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/stop_div/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/stop_div/test.gb b/cinema/gb/samesuite/apu/channel_2/stop_div/test.gb new file mode 100644 index 000000000..6c8d6e3fc Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/stop_div/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/stop_div/test.sym b/cinema/gb/samesuite/apu/channel_2/stop_div/test.sym new file mode 100644 index 000000000..ccb41512d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/stop_div/test.sym @@ -0,0 +1,46 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05e3 RunTest +00:05f9 TestGroup +00:0801 ShortTestGroup +00:0912 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/stop_div/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/stop_div/xbaseline_0000.png new file mode 100644 index 000000000..99bec969b Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/stop_div/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/stop_restart/config.ini b/cinema/gb/samesuite/apu/channel_2/stop_restart/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/stop_restart/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/stop_restart/test.gb b/cinema/gb/samesuite/apu/channel_2/stop_restart/test.gb new file mode 100644 index 000000000..66ef68f06 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/stop_restart/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/stop_restart/test.sym b/cinema/gb/samesuite/apu/channel_2/stop_restart/test.sym new file mode 100644 index 000000000..dcdf4b403 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/stop_restart/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:1f92 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/stop_restart/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/stop_restart/xbaseline_0000.png new file mode 100644 index 000000000..842c0c627 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/stop_restart/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/volume/config.ini b/cinema/gb/samesuite/apu/channel_2/volume/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/volume/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/volume/test.gb b/cinema/gb/samesuite/apu/channel_2/volume/test.gb new file mode 100644 index 000000000..34b005a47 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/volume/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/volume/test.sym b/cinema/gb/samesuite/apu/channel_2/volume/test.sym new file mode 100644 index 000000000..bd3d42fd4 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/volume/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:06e7 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/volume/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/volume/xbaseline_0000.png new file mode 100644 index 000000000..cb59bd6b2 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/volume/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_2/volume_div/config.ini b/cinema/gb/samesuite/apu/channel_2/volume_div/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/volume_div/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_2/volume_div/test.gb b/cinema/gb/samesuite/apu/channel_2/volume_div/test.gb new file mode 100644 index 000000000..27bf21d21 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/volume_div/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_2/volume_div/test.sym b/cinema/gb/samesuite/apu/channel_2/volume_div/test.sym new file mode 100644 index 000000000..8409a414e --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_2/volume_div/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:05db TestGroup +00:0804 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_2/volume_div/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_2/volume_div/xbaseline_0000.png new file mode 100644 index 000000000..e25e4f2ad Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_2/volume_div/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/and_glitch/config.ini b/cinema/gb/samesuite/apu/channel_3/and_glitch/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/and_glitch/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/and_glitch/test.gb b/cinema/gb/samesuite/apu/channel_3/and_glitch/test.gb new file mode 100644 index 000000000..623eed9fe Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/and_glitch/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/and_glitch/test.sym b/cinema/gb/samesuite/apu/channel_3/and_glitch/test.sym new file mode 100644 index 000000000..21f313c3e --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/and_glitch/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:145b StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/and_glitch/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/and_glitch/xbaseline_0000.png new file mode 100644 index 000000000..9a28b07ee Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/and_glitch/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/delay/config.ini b/cinema/gb/samesuite/apu/channel_3/delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/delay/test.gb b/cinema/gb/samesuite/apu/channel_3/delay/test.gb new file mode 100644 index 000000000..4c36bc173 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/delay/test.sym b/cinema/gb/samesuite/apu/channel_3/delay/test.sym new file mode 100644 index 000000000..3076b5b94 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:0895 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/delay/xbaseline_0000.png new file mode 100644 index 000000000..ff6fedbd8 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/config.ini b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/test.gb b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/test.gb new file mode 100644 index 000000000..71616256c Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/test.sym b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/test.sym new file mode 100644 index 000000000..8487ba99e --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:0a95 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/xbaseline_0000.png new file mode 100644 index 000000000..dc270dfc3 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgb0/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/config.ini b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/test.gb b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/test.gb new file mode 100644 index 000000000..74a355af1 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/test.sym b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/test.sym new file mode 100644 index 000000000..8487ba99e --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:0a95 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/xbaseline_0000.png new file mode 100644 index 000000000..b7f37174e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/extra_length_clocking-cgbB/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/first_sample/config.ini b/cinema/gb/samesuite/apu/channel_3/first_sample/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/first_sample/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/first_sample/test.gb b/cinema/gb/samesuite/apu/channel_3/first_sample/test.gb new file mode 100644 index 000000000..5bf9cdfd7 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/first_sample/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/first_sample/test.sym b/cinema/gb/samesuite/apu/channel_3/first_sample/test.sym new file mode 100644 index 000000000..5a9ec787b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/first_sample/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:073d StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/first_sample/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/first_sample/xbaseline_0000.png new file mode 100644 index 000000000..d37796fda Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/first_sample/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/freq_change_delay/config.ini b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/freq_change_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/test.gb new file mode 100644 index 000000000..216db98db Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/freq_change_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/test.sym new file mode 100644 index 000000000..82413a291 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:08d5 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/freq_change_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/xbaseline_0000.png new file mode 100644 index 000000000..9c3996d97 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/freq_change_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/restart_delay/baseline_0000.png b/cinema/gb/samesuite/apu/channel_3/restart_delay/baseline_0000.png new file mode 100644 index 000000000..1ebbf24f5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/restart_delay/baseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/restart_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/restart_delay/test.gb new file mode 100644 index 000000000..21f6777e7 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/restart_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/restart_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/restart_delay/test.sym new file mode 100644 index 000000000..5084d7002 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/restart_delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:0760 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/restart_during_delay/config.ini b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/restart_during_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/test.gb new file mode 100644 index 000000000..0d57843da Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/restart_during_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/test.sym new file mode 100644 index 000000000..298329bc3 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:05e1 TestGroup +00:0a52 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/restart_during_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/xbaseline_0000.png new file mode 100644 index 000000000..bb317a73e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/restart_during_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/config.ini b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/test.gb new file mode 100644 index 000000000..652f49d4f Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/test.sym new file mode 100644 index 000000000..c71922409 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:0887 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/xbaseline_0000.png new file mode 100644 index 000000000..6b865f6a4 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/restart_stop_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/shift_delay/baseline_0000.png b/cinema/gb/samesuite/apu/channel_3/shift_delay/baseline_0000.png new file mode 100644 index 000000000..60bdedff2 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/shift_delay/baseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/shift_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/shift_delay/test.gb new file mode 100644 index 000000000..c038ef468 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/shift_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/shift_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/shift_delay/test.sym new file mode 100644 index 000000000..5084d7002 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/shift_delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:0760 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/config.ini b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/test.gb new file mode 100644 index 000000000..5ba0f55d5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/test.sym new file mode 100644 index 000000000..0ff37b3f8 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:074d StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/xbaseline_0000.png new file mode 100644 index 000000000..d37796fda Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/shift_skip_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/stop_delay/config.ini b/cinema/gb/samesuite/apu/channel_3/stop_delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/stop_delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/stop_delay/test.gb b/cinema/gb/samesuite/apu/channel_3/stop_delay/test.gb new file mode 100644 index 000000000..01918cd5e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/stop_delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/stop_delay/test.sym b/cinema/gb/samesuite/apu/channel_3/stop_delay/test.sym new file mode 100644 index 000000000..cdba80c5c --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/stop_delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:074f StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/stop_delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/stop_delay/xbaseline_0000.png new file mode 100644 index 000000000..08605d056 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/stop_delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/stop_div/config.ini b/cinema/gb/samesuite/apu/channel_3/stop_div/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/stop_div/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/stop_div/test.gb b/cinema/gb/samesuite/apu/channel_3/stop_div/test.gb new file mode 100644 index 000000000..78b3bdac5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/stop_div/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/stop_div/test.sym b/cinema/gb/samesuite/apu/channel_3/stop_div/test.sym new file mode 100644 index 000000000..a94de9cad --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/stop_div/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:05f7 SubTestGroup +00:0980 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/stop_div/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/stop_div/xbaseline_0000.png new file mode 100644 index 000000000..5386fe3b3 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/stop_div/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/baseline_0000.png b/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/baseline_0000.png new file mode 100644 index 000000000..f1c82d032 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/baseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/test.gb b/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/test.gb new file mode 100644 index 000000000..4489a70a5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/test.sym b/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/test.sym new file mode 100644 index 000000000..a67599160 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/wave_ram_dac_on_rw/test.sym @@ -0,0 +1,48 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:05db CorrectResults.end +00:05f0 RunTest.initWaveRAM +00:0612 ReadWaveRAM +00:0615 ReadWaveRAM.loop +01:4000 NopSlide +00:c000 RESULTS_START diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/baseline_0000.png b/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/baseline_0000.png new file mode 100644 index 000000000..8c633955d Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/baseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/test.gb b/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/test.gb new file mode 100644 index 000000000..38c67595d Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/test.sym b/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/test.sym new file mode 100644 index 000000000..abaa17e35 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/wave_ram_locked_write/test.sym @@ -0,0 +1,53 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:065d RunTest.clearSMCBuffer +00:066d RunTest.subTest +00:0670 RunTest.initWaveRAM +00:0683 RunTest.copyWaveRAM +00:0697 RunTest.doSubTest +01:4000 NopSlide +00:c000 RESULTS_START +00:c090 SelfModifyingCodeBuffer +00:c090 ResultsBufferEnd +00:c09c SMCWritePtrLow +00:c09c SelfModifyingCodeBufferEnd diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/config.ini b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/test.gb b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/test.gb new file mode 100644 index 000000000..d6662f11a Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/test.sym b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/test.sym new file mode 100644 index 000000000..c3a3706e9 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05bb RunTest +00:05d1 TestGroup +00:07e2 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/xbaseline_0000.png new file mode 100644 index 000000000..c29819498 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_3/wave_ram_sync/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/align/config.ini b/cinema/gb/samesuite/apu/channel_4/align/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/align/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/align/test.gb b/cinema/gb/samesuite/apu/channel_4/align/test.gb new file mode 100644 index 000000000..ec45dc61e Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/align/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/align/test.sym b/cinema/gb/samesuite/apu/channel_4/align/test.sym new file mode 100644 index 000000000..c29866d1a --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/align/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05eb RunTest +00:0d55 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/align/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/align/xbaseline_0000.png new file mode 100644 index 000000000..68428b0d5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/align/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/delay/config.ini b/cinema/gb/samesuite/apu/channel_4/delay/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/delay/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/delay/test.gb b/cinema/gb/samesuite/apu/channel_4/delay/test.gb new file mode 100644 index 000000000..5d900d024 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/delay/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/delay/test.sym b/cinema/gb/samesuite/apu/channel_4/delay/test.sym new file mode 100644 index 000000000..1523a234d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/delay/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:095c StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/delay/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/delay/xbaseline_0000.png new file mode 100644 index 000000000..ce84afb70 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/delay/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/config.ini b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/test.gb b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/test.gb new file mode 100644 index 000000000..8c9aa69de Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/test.sym b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/test.sym new file mode 100644 index 000000000..12e97e4f2 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1431 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/xbaseline_0000.png new file mode 100644 index 000000000..38a3795cf Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/equivalent_frequencies/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/config.ini b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/test.gb b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/test.gb new file mode 100644 index 000000000..d114f5ac0 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/test.sym b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/test.sym new file mode 100644 index 000000000..947b9e80d --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05c3 RunTest +00:091d StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/xbaseline_0000.png new file mode 100644 index 000000000..6119a5f68 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/extra_length_clocking-cgb0B/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/freq_change/config.ini b/cinema/gb/samesuite/apu/channel_4/freq_change/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/freq_change/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/freq_change/test.gb b/cinema/gb/samesuite/apu/channel_4/freq_change/test.gb new file mode 100644 index 000000000..153b7abd5 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/freq_change/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/freq_change/test.sym b/cinema/gb/samesuite/apu/channel_4/freq_change/test.sym new file mode 100644 index 000000000..29fd7a580 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/freq_change/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05eb RunTest +00:0eaf StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/freq_change/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/freq_change/xbaseline_0000.png new file mode 100644 index 000000000..e1ec0cdd9 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/freq_change/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/frequency_alignment/config.ini b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/frequency_alignment/test.gb b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/test.gb new file mode 100644 index 000000000..b60a62200 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/frequency_alignment/test.sym b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/test.sym new file mode 100644 index 000000000..cb91fb5d8 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:063b RunTest +00:1768 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/frequency_alignment/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/xbaseline_0000.png new file mode 100644 index 000000000..f77e3c8b1 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/frequency_alignment/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr/config.ini b/cinema/gb/samesuite/apu/channel_4/lfsr/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr/test.gb b/cinema/gb/samesuite/apu/channel_4/lfsr/test.gb new file mode 100644 index 000000000..879492218 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr/test.sym b/cinema/gb/samesuite/apu/channel_4/lfsr/test.sym new file mode 100644 index 000000000..8bf35e53f --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1511 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/lfsr/xbaseline_0000.png new file mode 100644 index 000000000..f58f4c214 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr15/config.ini b/cinema/gb/samesuite/apu/channel_4/lfsr15/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr15/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr15/test.gb b/cinema/gb/samesuite/apu/channel_4/lfsr15/test.gb new file mode 100644 index 000000000..82164ad20 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr15/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr15/test.sym b/cinema/gb/samesuite/apu/channel_4/lfsr15/test.sym new file mode 100644 index 000000000..7cda89079 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr15/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1489 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr15/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/lfsr15/xbaseline_0000.png new file mode 100644 index 000000000..f987e3982 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr15/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/config.ini b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/test.gb b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/test.gb new file mode 100644 index 000000000..211fda068 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/test.sym b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/test.sym new file mode 100644 index 000000000..e6060af1f --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1954 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/xbaseline_0000.png new file mode 100644 index 000000000..2c83204a8 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_15_7/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/config.ini b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/test.gb b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/test.gb new file mode 100644 index 000000000..68d330b95 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/test.sym b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/test.sym new file mode 100644 index 000000000..e6060af1f --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1954 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/xbaseline_0000.png new file mode 100644 index 000000000..c965f51b7 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_7_15/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart/config.ini b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart/test.gb b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/test.gb new file mode 100644 index 000000000..67806ea6c Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart/test.sym b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/test.sym new file mode 100644 index 000000000..0fe12197b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:17b9 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/xbaseline_0000.png new file mode 100644 index 000000000..d425c2d3f Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_restart/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/config.ini b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/test.gb b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/test.gb new file mode 100644 index 000000000..46fb4e418 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/test.sym b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/test.sym new file mode 100644 index 000000000..31a200412 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/test.sym @@ -0,0 +1,44 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b RunTest +00:1621 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/xbaseline_0000.png b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/xbaseline_0000.png new file mode 100644 index 000000000..d425c2d3f Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/lfsr_restart_fast/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/volume_div/baseline_0000.png b/cinema/gb/samesuite/apu/channel_4/volume_div/baseline_0000.png new file mode 100644 index 000000000..189f5f289 Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/volume_div/baseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/channel_4/volume_div/config.ini b/cinema/gb/samesuite/apu/channel_4/volume_div/config.ini new file mode 100644 index 000000000..da67580a4 --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/volume_div/config.ini @@ -0,0 +1,2 @@ +[testinfo] +skip=120 diff --git a/cinema/gb/samesuite/apu/channel_4/volume_div/test.gb b/cinema/gb/samesuite/apu/channel_4/volume_div/test.gb new file mode 100644 index 000000000..5cdb7be8c Binary files /dev/null and b/cinema/gb/samesuite/apu/channel_4/volume_div/test.gb differ diff --git a/cinema/gb/samesuite/apu/channel_4/volume_div/test.sym b/cinema/gb/samesuite/apu/channel_4/volume_div/test.sym new file mode 100644 index 000000000..36b01a6dc --- /dev/null +++ b/cinema/gb/samesuite/apu/channel_4/volume_div/test.sym @@ -0,0 +1,45 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05eb RunTest +00:05fb TestGroup +00:0a7c StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/div_trigger_volume_10/baseline_0000.png b/cinema/gb/samesuite/apu/div_trigger_volume_10/baseline_0000.png new file mode 100644 index 000000000..3cdc8e21b Binary files /dev/null and b/cinema/gb/samesuite/apu/div_trigger_volume_10/baseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/div_trigger_volume_10/config.ini b/cinema/gb/samesuite/apu/div_trigger_volume_10/config.ini new file mode 100644 index 000000000..8f7eb1c12 --- /dev/null +++ b/cinema/gb/samesuite/apu/div_trigger_volume_10/config.ini @@ -0,0 +1,2 @@ +[testinfo] +skip=80 diff --git a/cinema/gb/samesuite/apu/div_trigger_volume_10/test.gb b/cinema/gb/samesuite/apu/div_trigger_volume_10/test.gb new file mode 100644 index 000000000..942cd8049 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_trigger_volume_10/test.gb differ diff --git a/cinema/gb/samesuite/apu/div_trigger_volume_10/test.sym b/cinema/gb/samesuite/apu/div_trigger_volume_10/test.sym new file mode 100644 index 000000000..ceca33fa2 --- /dev/null +++ b/cinema/gb/samesuite/apu/div_trigger_volume_10/test.sym @@ -0,0 +1,305 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb WaitDIVEvent +00:05cb WaitDIVEvent.waitOn +00:05cf WaitDIVEvent.waitOff +00:05d4 WaitDIV10 +00:05d6 WaitDIV10.waitDIV +00:05da RunTest +00:0602 RunTest.done_u16403 +00:0608 RunTest.done_u16405 +00:060e RunTest.done_u16407 +00:0614 RunTest.done_u16409 +00:061a RunTest.done_u16411 +00:0620 RunTest.done_u16413 +00:0626 RunTest.done_u16415 +00:062c RunTest.done_u16417 +00:0657 RunTest.done_u16421 +00:065d RunTest.done_u16423 +00:0663 RunTest.done_u16425 +00:0669 RunTest.done_u16427 +00:066f RunTest.done_u16429 +00:0675 RunTest.done_u16431 +00:067b RunTest.done_u16433 +00:0681 RunTest.done_u16435 +00:06af RunTest.done_u16440 +00:06b5 RunTest.done_u16442 +00:06bb RunTest.done_u16444 +00:06c1 RunTest.done_u16446 +00:06c7 RunTest.done_u16448 +00:06cd RunTest.done_u16450 +00:06d3 RunTest.done_u16452 +00:06d9 RunTest.done_u16454 +00:070a RunTest.done_u16460 +00:0710 RunTest.done_u16462 +00:0716 RunTest.done_u16464 +00:071c RunTest.done_u16466 +00:0722 RunTest.done_u16468 +00:0728 RunTest.done_u16470 +00:072e RunTest.done_u16472 +00:0734 RunTest.done_u16474 +00:0768 RunTest.done_u16481 +00:076e RunTest.done_u16483 +00:0774 RunTest.done_u16485 +00:077a RunTest.done_u16487 +00:0780 RunTest.done_u16489 +00:0786 RunTest.done_u16491 +00:078c RunTest.done_u16493 +00:0792 RunTest.done_u16495 +00:07c9 RunTest.done_u16503 +00:07cf RunTest.done_u16505 +00:07d5 RunTest.done_u16507 +00:07db RunTest.done_u16509 +00:07e1 RunTest.done_u16511 +00:07e7 RunTest.done_u16513 +00:07ed RunTest.done_u16515 +00:07f3 RunTest.done_u16517 +00:082d RunTest.done_u16526 +00:0833 RunTest.done_u16528 +00:0839 RunTest.done_u16530 +00:083f RunTest.done_u16532 +00:0845 RunTest.done_u16534 +00:084b RunTest.done_u16536 +00:0851 RunTest.done_u16538 +00:0857 RunTest.done_u16540 +00:0894 RunTest.done_u16550 +00:089a RunTest.done_u16552 +00:08a0 RunTest.done_u16554 +00:08a6 RunTest.done_u16556 +00:08ac RunTest.done_u16558 +00:08b2 RunTest.done_u16560 +00:08b8 RunTest.done_u16562 +00:08be RunTest.done_u16564 +00:08fe RunTest.done_u16575 +00:0904 RunTest.done_u16577 +00:090a RunTest.done_u16579 +00:0910 RunTest.done_u16581 +00:0916 RunTest.done_u16583 +00:091c RunTest.done_u16585 +00:0922 RunTest.done_u16587 +00:0928 RunTest.done_u16589 +00:096b RunTest.done_u16601 +00:0971 RunTest.done_u16603 +00:0977 RunTest.done_u16605 +00:097d RunTest.done_u16607 +00:0983 RunTest.done_u16609 +00:0989 RunTest.done_u16611 +00:098f RunTest.done_u16613 +00:0995 RunTest.done_u16615 +00:09db RunTest.done_u16628 +00:09e1 RunTest.done_u16630 +00:09e7 RunTest.done_u16632 +00:09ed RunTest.done_u16634 +00:09f3 RunTest.done_u16636 +00:09f9 RunTest.done_u16638 +00:09ff RunTest.done_u16640 +00:0a05 RunTest.done_u16642 +00:0a4e RunTest.done_u16656 +00:0a54 RunTest.done_u16658 +00:0a5a RunTest.done_u16660 +00:0a60 RunTest.done_u16662 +00:0a66 RunTest.done_u16664 +00:0a6c RunTest.done_u16666 +00:0a72 RunTest.done_u16668 +00:0a78 RunTest.done_u16670 +00:0ac4 RunTest.done_u16685 +00:0aca RunTest.done_u16687 +00:0ad0 RunTest.done_u16689 +00:0ad6 RunTest.done_u16691 +00:0adc RunTest.done_u16693 +00:0ae2 RunTest.done_u16695 +00:0ae8 RunTest.done_u16697 +00:0aee RunTest.done_u16699 +00:0b3d RunTest.done_u16715 +00:0b43 RunTest.done_u16717 +00:0b49 RunTest.done_u16719 +00:0b4f RunTest.done_u16721 +00:0b55 RunTest.done_u16723 +00:0b5b RunTest.done_u16725 +00:0b61 RunTest.done_u16727 +00:0b67 RunTest.done_u16729 +00:0bb9 RunTest.done_u16746 +00:0bbf RunTest.done_u16748 +00:0bc5 RunTest.done_u16750 +00:0bcb RunTest.done_u16752 +00:0bd1 RunTest.done_u16754 +00:0bd7 RunTest.done_u16756 +00:0bdd RunTest.done_u16758 +00:0be3 RunTest.done_u16760 +00:0c38 RunTest.done_u16778 +00:0c3e RunTest.done_u16780 +00:0c44 RunTest.done_u16782 +00:0c4a RunTest.done_u16784 +00:0c50 RunTest.done_u16786 +00:0c56 RunTest.done_u16788 +00:0c5c RunTest.done_u16790 +00:0c62 RunTest.done_u16792 +00:0cba RunTest.done_u16811 +00:0cc0 RunTest.done_u16813 +00:0cc6 RunTest.done_u16815 +00:0ccc RunTest.done_u16817 +00:0cd2 RunTest.done_u16819 +00:0cd8 RunTest.done_u16821 +00:0cde RunTest.done_u16823 +00:0ce4 RunTest.done_u16825 +00:0d3f RunTest.done_u16845 +00:0d45 RunTest.done_u16847 +00:0d4b RunTest.done_u16849 +00:0d51 RunTest.done_u16851 +00:0d57 RunTest.done_u16853 +00:0d5d RunTest.done_u16855 +00:0d63 RunTest.done_u16857 +00:0d69 RunTest.done_u16859 +00:0dc7 RunTest.done_u16880 +00:0dcd RunTest.done_u16882 +00:0dd3 RunTest.done_u16884 +00:0dd9 RunTest.done_u16886 +00:0ddf RunTest.done_u16888 +00:0de5 RunTest.done_u16890 +00:0deb RunTest.done_u16892 +00:0df1 RunTest.done_u16894 +00:0e52 RunTest.done_u16916 +00:0e58 RunTest.done_u16918 +00:0e5e RunTest.done_u16920 +00:0e64 RunTest.done_u16922 +00:0e6a RunTest.done_u16924 +00:0e70 RunTest.done_u16926 +00:0e76 RunTest.done_u16928 +00:0e7c RunTest.done_u16930 +00:0ee0 RunTest.done_u16953 +00:0ee6 RunTest.done_u16955 +00:0eec RunTest.done_u16957 +00:0ef2 RunTest.done_u16959 +00:0ef8 RunTest.done_u16961 +00:0efe RunTest.done_u16963 +00:0f04 RunTest.done_u16965 +00:0f0a RunTest.done_u16967 +00:0f71 RunTest.done_u16991 +00:0f77 RunTest.done_u16993 +00:0f7d RunTest.done_u16995 +00:0f83 RunTest.done_u16997 +00:0f89 RunTest.done_u16999 +00:0f8f RunTest.done_u17001 +00:0f95 RunTest.done_u17003 +00:0f9b RunTest.done_u17005 +00:1005 RunTest.done_u17030 +00:100b RunTest.done_u17032 +00:1011 RunTest.done_u17034 +00:1017 RunTest.done_u17036 +00:101d RunTest.done_u17038 +00:1023 RunTest.done_u17040 +00:1029 RunTest.done_u17042 +00:102f RunTest.done_u17044 +00:109c RunTest.done_u17070 +00:10a2 RunTest.done_u17072 +00:10a8 RunTest.done_u17074 +00:10ae RunTest.done_u17076 +00:10b4 RunTest.done_u17078 +00:10ba RunTest.done_u17080 +00:10c0 RunTest.done_u17082 +00:10c6 RunTest.done_u17084 +00:1136 RunTest.done_u17111 +00:113c RunTest.done_u17113 +00:1142 RunTest.done_u17115 +00:1148 RunTest.done_u17117 +00:114e RunTest.done_u17119 +00:1154 RunTest.done_u17121 +00:115a RunTest.done_u17123 +00:1160 RunTest.done_u17125 +00:11d3 RunTest.done_u17153 +00:11d9 RunTest.done_u17155 +00:11df RunTest.done_u17157 +00:11e5 RunTest.done_u17159 +00:11eb RunTest.done_u17161 +00:11f1 RunTest.done_u17163 +00:11f7 RunTest.done_u17165 +00:11fd RunTest.done_u17167 +00:1273 RunTest.done_u17196 +00:1279 RunTest.done_u17198 +00:127f RunTest.done_u17200 +00:1285 RunTest.done_u17202 +00:128b RunTest.done_u17204 +00:1291 RunTest.done_u17206 +00:1297 RunTest.done_u17208 +00:129d RunTest.done_u17210 +00:1316 RunTest.done_u17240 +00:131c RunTest.done_u17242 +00:1322 RunTest.done_u17244 +00:1328 RunTest.done_u17246 +00:132e RunTest.done_u17248 +00:1334 RunTest.done_u17250 +00:133a RunTest.done_u17252 +00:1340 RunTest.done_u17254 +00:13bc RunTest.done_u17285 +00:13c2 RunTest.done_u17287 +00:13c8 RunTest.done_u17289 +00:13ce RunTest.done_u17291 +00:13d4 RunTest.done_u17293 +00:13da RunTest.done_u17295 +00:13e0 RunTest.done_u17297 +00:13e6 RunTest.done_u17299 +00:1465 RunTest.done_u17331 +00:146b RunTest.done_u17333 +00:1471 RunTest.done_u17335 +00:1477 RunTest.done_u17337 +00:147d RunTest.done_u17339 +00:1483 RunTest.done_u17341 +00:1489 RunTest.done_u17343 +00:148f RunTest.done_u17345 +00:1511 RunTest.done_u17378 +00:1517 RunTest.done_u17380 +00:151d RunTest.done_u17382 +00:1523 RunTest.done_u17384 +00:1529 RunTest.done_u17386 +00:152f RunTest.done_u17388 +00:1535 RunTest.done_u17390 +00:153b RunTest.done_u17392 +00:15c0 RunTest.done_u17426 +00:15c6 RunTest.done_u17428 +00:15cc RunTest.done_u17430 +00:15d2 RunTest.done_u17432 +00:15d8 RunTest.done_u17434 +00:15de RunTest.done_u17436 +00:15e4 RunTest.done_u17438 +00:15ea RunTest.done_u17440 +00:15ee StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/div_write_trigger/config.ini b/cinema/gb/samesuite/apu/div_write_trigger/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/div_write_trigger/test.gb b/cinema/gb/samesuite/apu/div_write_trigger/test.gb new file mode 100644 index 000000000..43c2ce2a9 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger/test.gb differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger/test.sym b/cinema/gb/samesuite/apu/div_write_trigger/test.sym new file mode 100644 index 000000000..f78eebc84 --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger/test.sym @@ -0,0 +1,46 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b TriggerAPU +00:062d TriggerAPU.waitDIV +00:0632 RunTest +00:1e76 StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/div_write_trigger/xbaseline_0000.png b/cinema/gb/samesuite/apu/div_write_trigger/xbaseline_0000.png new file mode 100644 index 000000000..a37111821 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger_10/config.ini b/cinema/gb/samesuite/apu/div_write_trigger_10/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger_10/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/div_write_trigger_10/test.gb b/cinema/gb/samesuite/apu/div_write_trigger_10/test.gb new file mode 100644 index 000000000..7f82952c0 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger_10/test.gb differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger_10/test.sym b/cinema/gb/samesuite/apu/div_write_trigger_10/test.sym new file mode 100644 index 000000000..b6b5cc43d --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger_10/test.sym @@ -0,0 +1,47 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:062b TriggerAPU +00:0630 WaitDIV10 +00:0632 WaitDIV10.waitDIV +00:0636 RunTest +00:1ffa StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/div_write_trigger_10/xbaseline_0000.png b/cinema/gb/samesuite/apu/div_write_trigger_10/xbaseline_0000.png new file mode 100644 index 000000000..b8f75bf0b Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger_10/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume/config.ini b/cinema/gb/samesuite/apu/div_write_trigger_volume/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger_volume/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume/test.gb b/cinema/gb/samesuite/apu/div_write_trigger_volume/test.gb new file mode 100644 index 000000000..c8c137e51 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger_volume/test.gb differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume/test.sym b/cinema/gb/samesuite/apu/div_write_trigger_volume/test.sym new file mode 100644 index 000000000..b0f84055f --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger_volume/test.sym @@ -0,0 +1,303 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb TriggerAPU +00:05d0 WaitDIV10 +00:05d2 WaitDIV10.waitDIV +00:05d6 RunTest +00:05fb RunTest.done_u16403 +00:0601 RunTest.done_u16405 +00:0607 RunTest.done_u16407 +00:060d RunTest.done_u16409 +00:0613 RunTest.done_u16411 +00:0619 RunTest.done_u16413 +00:061f RunTest.done_u16415 +00:0625 RunTest.done_u16417 +00:064d RunTest.done_u16421 +00:0653 RunTest.done_u16423 +00:0659 RunTest.done_u16425 +00:065f RunTest.done_u16427 +00:0665 RunTest.done_u16429 +00:066b RunTest.done_u16431 +00:0671 RunTest.done_u16433 +00:0677 RunTest.done_u16435 +00:06a2 RunTest.done_u16440 +00:06a8 RunTest.done_u16442 +00:06ae RunTest.done_u16444 +00:06b4 RunTest.done_u16446 +00:06ba RunTest.done_u16448 +00:06c0 RunTest.done_u16450 +00:06c6 RunTest.done_u16452 +00:06cc RunTest.done_u16454 +00:06fa RunTest.done_u16460 +00:0700 RunTest.done_u16462 +00:0706 RunTest.done_u16464 +00:070c RunTest.done_u16466 +00:0712 RunTest.done_u16468 +00:0718 RunTest.done_u16470 +00:071e RunTest.done_u16472 +00:0724 RunTest.done_u16474 +00:0755 RunTest.done_u16481 +00:075b RunTest.done_u16483 +00:0761 RunTest.done_u16485 +00:0767 RunTest.done_u16487 +00:076d RunTest.done_u16489 +00:0773 RunTest.done_u16491 +00:0779 RunTest.done_u16493 +00:077f RunTest.done_u16495 +00:07b3 RunTest.done_u16503 +00:07b9 RunTest.done_u16505 +00:07bf RunTest.done_u16507 +00:07c5 RunTest.done_u16509 +00:07cb RunTest.done_u16511 +00:07d1 RunTest.done_u16513 +00:07d7 RunTest.done_u16515 +00:07dd RunTest.done_u16517 +00:0814 RunTest.done_u16526 +00:081a RunTest.done_u16528 +00:0820 RunTest.done_u16530 +00:0826 RunTest.done_u16532 +00:082c RunTest.done_u16534 +00:0832 RunTest.done_u16536 +00:0838 RunTest.done_u16538 +00:083e RunTest.done_u16540 +00:0878 RunTest.done_u16550 +00:087e RunTest.done_u16552 +00:0884 RunTest.done_u16554 +00:088a RunTest.done_u16556 +00:0890 RunTest.done_u16558 +00:0896 RunTest.done_u16560 +00:089c RunTest.done_u16562 +00:08a2 RunTest.done_u16564 +00:08df RunTest.done_u16575 +00:08e5 RunTest.done_u16577 +00:08eb RunTest.done_u16579 +00:08f1 RunTest.done_u16581 +00:08f7 RunTest.done_u16583 +00:08fd RunTest.done_u16585 +00:0903 RunTest.done_u16587 +00:0909 RunTest.done_u16589 +00:0949 RunTest.done_u16601 +00:094f RunTest.done_u16603 +00:0955 RunTest.done_u16605 +00:095b RunTest.done_u16607 +00:0961 RunTest.done_u16609 +00:0967 RunTest.done_u16611 +00:096d RunTest.done_u16613 +00:0973 RunTest.done_u16615 +00:09b6 RunTest.done_u16628 +00:09bc RunTest.done_u16630 +00:09c2 RunTest.done_u16632 +00:09c8 RunTest.done_u16634 +00:09ce RunTest.done_u16636 +00:09d4 RunTest.done_u16638 +00:09da RunTest.done_u16640 +00:09e0 RunTest.done_u16642 +00:0a26 RunTest.done_u16656 +00:0a2c RunTest.done_u16658 +00:0a32 RunTest.done_u16660 +00:0a38 RunTest.done_u16662 +00:0a3e RunTest.done_u16664 +00:0a44 RunTest.done_u16666 +00:0a4a RunTest.done_u16668 +00:0a50 RunTest.done_u16670 +00:0a99 RunTest.done_u16685 +00:0a9f RunTest.done_u16687 +00:0aa5 RunTest.done_u16689 +00:0aab RunTest.done_u16691 +00:0ab1 RunTest.done_u16693 +00:0ab7 RunTest.done_u16695 +00:0abd RunTest.done_u16697 +00:0ac3 RunTest.done_u16699 +00:0b0f RunTest.done_u16715 +00:0b15 RunTest.done_u16717 +00:0b1b RunTest.done_u16719 +00:0b21 RunTest.done_u16721 +00:0b27 RunTest.done_u16723 +00:0b2d RunTest.done_u16725 +00:0b33 RunTest.done_u16727 +00:0b39 RunTest.done_u16729 +00:0b88 RunTest.done_u16746 +00:0b8e RunTest.done_u16748 +00:0b94 RunTest.done_u16750 +00:0b9a RunTest.done_u16752 +00:0ba0 RunTest.done_u16754 +00:0ba6 RunTest.done_u16756 +00:0bac RunTest.done_u16758 +00:0bb2 RunTest.done_u16760 +00:0c04 RunTest.done_u16778 +00:0c0a RunTest.done_u16780 +00:0c10 RunTest.done_u16782 +00:0c16 RunTest.done_u16784 +00:0c1c RunTest.done_u16786 +00:0c22 RunTest.done_u16788 +00:0c28 RunTest.done_u16790 +00:0c2e RunTest.done_u16792 +00:0c83 RunTest.done_u16811 +00:0c89 RunTest.done_u16813 +00:0c8f RunTest.done_u16815 +00:0c95 RunTest.done_u16817 +00:0c9b RunTest.done_u16819 +00:0ca1 RunTest.done_u16821 +00:0ca7 RunTest.done_u16823 +00:0cad RunTest.done_u16825 +00:0d05 RunTest.done_u16845 +00:0d0b RunTest.done_u16847 +00:0d11 RunTest.done_u16849 +00:0d17 RunTest.done_u16851 +00:0d1d RunTest.done_u16853 +00:0d23 RunTest.done_u16855 +00:0d29 RunTest.done_u16857 +00:0d2f RunTest.done_u16859 +00:0d8a RunTest.done_u16880 +00:0d90 RunTest.done_u16882 +00:0d96 RunTest.done_u16884 +00:0d9c RunTest.done_u16886 +00:0da2 RunTest.done_u16888 +00:0da8 RunTest.done_u16890 +00:0dae RunTest.done_u16892 +00:0db4 RunTest.done_u16894 +00:0e12 RunTest.done_u16916 +00:0e18 RunTest.done_u16918 +00:0e1e RunTest.done_u16920 +00:0e24 RunTest.done_u16922 +00:0e2a RunTest.done_u16924 +00:0e30 RunTest.done_u16926 +00:0e36 RunTest.done_u16928 +00:0e3c RunTest.done_u16930 +00:0e9d RunTest.done_u16953 +00:0ea3 RunTest.done_u16955 +00:0ea9 RunTest.done_u16957 +00:0eaf RunTest.done_u16959 +00:0eb5 RunTest.done_u16961 +00:0ebb RunTest.done_u16963 +00:0ec1 RunTest.done_u16965 +00:0ec7 RunTest.done_u16967 +00:0f2b RunTest.done_u16991 +00:0f31 RunTest.done_u16993 +00:0f37 RunTest.done_u16995 +00:0f3d RunTest.done_u16997 +00:0f43 RunTest.done_u16999 +00:0f49 RunTest.done_u17001 +00:0f4f RunTest.done_u17003 +00:0f55 RunTest.done_u17005 +00:0fbc RunTest.done_u17030 +00:0fc2 RunTest.done_u17032 +00:0fc8 RunTest.done_u17034 +00:0fce RunTest.done_u17036 +00:0fd4 RunTest.done_u17038 +00:0fda RunTest.done_u17040 +00:0fe0 RunTest.done_u17042 +00:0fe6 RunTest.done_u17044 +00:1050 RunTest.done_u17070 +00:1056 RunTest.done_u17072 +00:105c RunTest.done_u17074 +00:1062 RunTest.done_u17076 +00:1068 RunTest.done_u17078 +00:106e RunTest.done_u17080 +00:1074 RunTest.done_u17082 +00:107a RunTest.done_u17084 +00:10e7 RunTest.done_u17111 +00:10ed RunTest.done_u17113 +00:10f3 RunTest.done_u17115 +00:10f9 RunTest.done_u17117 +00:10ff RunTest.done_u17119 +00:1105 RunTest.done_u17121 +00:110b RunTest.done_u17123 +00:1111 RunTest.done_u17125 +00:1181 RunTest.done_u17153 +00:1187 RunTest.done_u17155 +00:118d RunTest.done_u17157 +00:1193 RunTest.done_u17159 +00:1199 RunTest.done_u17161 +00:119f RunTest.done_u17163 +00:11a5 RunTest.done_u17165 +00:11ab RunTest.done_u17167 +00:121e RunTest.done_u17196 +00:1224 RunTest.done_u17198 +00:122a RunTest.done_u17200 +00:1230 RunTest.done_u17202 +00:1236 RunTest.done_u17204 +00:123c RunTest.done_u17206 +00:1242 RunTest.done_u17208 +00:1248 RunTest.done_u17210 +00:12be RunTest.done_u17240 +00:12c4 RunTest.done_u17242 +00:12ca RunTest.done_u17244 +00:12d0 RunTest.done_u17246 +00:12d6 RunTest.done_u17248 +00:12dc RunTest.done_u17250 +00:12e2 RunTest.done_u17252 +00:12e8 RunTest.done_u17254 +00:1361 RunTest.done_u17285 +00:1367 RunTest.done_u17287 +00:136d RunTest.done_u17289 +00:1373 RunTest.done_u17291 +00:1379 RunTest.done_u17293 +00:137f RunTest.done_u17295 +00:1385 RunTest.done_u17297 +00:138b RunTest.done_u17299 +00:1407 RunTest.done_u17331 +00:140d RunTest.done_u17333 +00:1413 RunTest.done_u17335 +00:1419 RunTest.done_u17337 +00:141f RunTest.done_u17339 +00:1425 RunTest.done_u17341 +00:142b RunTest.done_u17343 +00:1431 RunTest.done_u17345 +00:14b0 RunTest.done_u17378 +00:14b6 RunTest.done_u17380 +00:14bc RunTest.done_u17382 +00:14c2 RunTest.done_u17384 +00:14c8 RunTest.done_u17386 +00:14ce RunTest.done_u17388 +00:14d4 RunTest.done_u17390 +00:14da RunTest.done_u17392 +00:155c RunTest.done_u17426 +00:1562 RunTest.done_u17428 +00:1568 RunTest.done_u17430 +00:156e RunTest.done_u17432 +00:1574 RunTest.done_u17434 +00:157a RunTest.done_u17436 +00:1580 RunTest.done_u17438 +00:1586 RunTest.done_u17440 +00:158a StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume/xbaseline_0000.png b/cinema/gb/samesuite/apu/div_write_trigger_volume/xbaseline_0000.png new file mode 100644 index 000000000..1faa3d928 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger_volume/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume_10/config.ini b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume_10/test.gb b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/test.gb new file mode 100644 index 000000000..0e911652c Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/test.gb differ diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume_10/test.sym b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/test.sym new file mode 100644 index 000000000..48706594f --- /dev/null +++ b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/test.sym @@ -0,0 +1,303 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb TriggerAPU +00:05d0 WaitDIV10 +00:05d2 WaitDIV10.waitDIV +00:05d6 RunTest +00:05fe RunTest.done_u16403 +00:0604 RunTest.done_u16405 +00:060a RunTest.done_u16407 +00:0610 RunTest.done_u16409 +00:0616 RunTest.done_u16411 +00:061c RunTest.done_u16413 +00:0622 RunTest.done_u16415 +00:0628 RunTest.done_u16417 +00:0653 RunTest.done_u16421 +00:0659 RunTest.done_u16423 +00:065f RunTest.done_u16425 +00:0665 RunTest.done_u16427 +00:066b RunTest.done_u16429 +00:0671 RunTest.done_u16431 +00:0677 RunTest.done_u16433 +00:067d RunTest.done_u16435 +00:06ab RunTest.done_u16440 +00:06b1 RunTest.done_u16442 +00:06b7 RunTest.done_u16444 +00:06bd RunTest.done_u16446 +00:06c3 RunTest.done_u16448 +00:06c9 RunTest.done_u16450 +00:06cf RunTest.done_u16452 +00:06d5 RunTest.done_u16454 +00:0706 RunTest.done_u16460 +00:070c RunTest.done_u16462 +00:0712 RunTest.done_u16464 +00:0718 RunTest.done_u16466 +00:071e RunTest.done_u16468 +00:0724 RunTest.done_u16470 +00:072a RunTest.done_u16472 +00:0730 RunTest.done_u16474 +00:0764 RunTest.done_u16481 +00:076a RunTest.done_u16483 +00:0770 RunTest.done_u16485 +00:0776 RunTest.done_u16487 +00:077c RunTest.done_u16489 +00:0782 RunTest.done_u16491 +00:0788 RunTest.done_u16493 +00:078e RunTest.done_u16495 +00:07c5 RunTest.done_u16503 +00:07cb RunTest.done_u16505 +00:07d1 RunTest.done_u16507 +00:07d7 RunTest.done_u16509 +00:07dd RunTest.done_u16511 +00:07e3 RunTest.done_u16513 +00:07e9 RunTest.done_u16515 +00:07ef RunTest.done_u16517 +00:0829 RunTest.done_u16526 +00:082f RunTest.done_u16528 +00:0835 RunTest.done_u16530 +00:083b RunTest.done_u16532 +00:0841 RunTest.done_u16534 +00:0847 RunTest.done_u16536 +00:084d RunTest.done_u16538 +00:0853 RunTest.done_u16540 +00:0890 RunTest.done_u16550 +00:0896 RunTest.done_u16552 +00:089c RunTest.done_u16554 +00:08a2 RunTest.done_u16556 +00:08a8 RunTest.done_u16558 +00:08ae RunTest.done_u16560 +00:08b4 RunTest.done_u16562 +00:08ba RunTest.done_u16564 +00:08fa RunTest.done_u16575 +00:0900 RunTest.done_u16577 +00:0906 RunTest.done_u16579 +00:090c RunTest.done_u16581 +00:0912 RunTest.done_u16583 +00:0918 RunTest.done_u16585 +00:091e RunTest.done_u16587 +00:0924 RunTest.done_u16589 +00:0967 RunTest.done_u16601 +00:096d RunTest.done_u16603 +00:0973 RunTest.done_u16605 +00:0979 RunTest.done_u16607 +00:097f RunTest.done_u16609 +00:0985 RunTest.done_u16611 +00:098b RunTest.done_u16613 +00:0991 RunTest.done_u16615 +00:09d7 RunTest.done_u16628 +00:09dd RunTest.done_u16630 +00:09e3 RunTest.done_u16632 +00:09e9 RunTest.done_u16634 +00:09ef RunTest.done_u16636 +00:09f5 RunTest.done_u16638 +00:09fb RunTest.done_u16640 +00:0a01 RunTest.done_u16642 +00:0a4a RunTest.done_u16656 +00:0a50 RunTest.done_u16658 +00:0a56 RunTest.done_u16660 +00:0a5c RunTest.done_u16662 +00:0a62 RunTest.done_u16664 +00:0a68 RunTest.done_u16666 +00:0a6e RunTest.done_u16668 +00:0a74 RunTest.done_u16670 +00:0ac0 RunTest.done_u16685 +00:0ac6 RunTest.done_u16687 +00:0acc RunTest.done_u16689 +00:0ad2 RunTest.done_u16691 +00:0ad8 RunTest.done_u16693 +00:0ade RunTest.done_u16695 +00:0ae4 RunTest.done_u16697 +00:0aea RunTest.done_u16699 +00:0b39 RunTest.done_u16715 +00:0b3f RunTest.done_u16717 +00:0b45 RunTest.done_u16719 +00:0b4b RunTest.done_u16721 +00:0b51 RunTest.done_u16723 +00:0b57 RunTest.done_u16725 +00:0b5d RunTest.done_u16727 +00:0b63 RunTest.done_u16729 +00:0bb5 RunTest.done_u16746 +00:0bbb RunTest.done_u16748 +00:0bc1 RunTest.done_u16750 +00:0bc7 RunTest.done_u16752 +00:0bcd RunTest.done_u16754 +00:0bd3 RunTest.done_u16756 +00:0bd9 RunTest.done_u16758 +00:0bdf RunTest.done_u16760 +00:0c34 RunTest.done_u16778 +00:0c3a RunTest.done_u16780 +00:0c40 RunTest.done_u16782 +00:0c46 RunTest.done_u16784 +00:0c4c RunTest.done_u16786 +00:0c52 RunTest.done_u16788 +00:0c58 RunTest.done_u16790 +00:0c5e RunTest.done_u16792 +00:0cb6 RunTest.done_u16811 +00:0cbc RunTest.done_u16813 +00:0cc2 RunTest.done_u16815 +00:0cc8 RunTest.done_u16817 +00:0cce RunTest.done_u16819 +00:0cd4 RunTest.done_u16821 +00:0cda RunTest.done_u16823 +00:0ce0 RunTest.done_u16825 +00:0d3b RunTest.done_u16845 +00:0d41 RunTest.done_u16847 +00:0d47 RunTest.done_u16849 +00:0d4d RunTest.done_u16851 +00:0d53 RunTest.done_u16853 +00:0d59 RunTest.done_u16855 +00:0d5f RunTest.done_u16857 +00:0d65 RunTest.done_u16859 +00:0dc3 RunTest.done_u16880 +00:0dc9 RunTest.done_u16882 +00:0dcf RunTest.done_u16884 +00:0dd5 RunTest.done_u16886 +00:0ddb RunTest.done_u16888 +00:0de1 RunTest.done_u16890 +00:0de7 RunTest.done_u16892 +00:0ded RunTest.done_u16894 +00:0e4e RunTest.done_u16916 +00:0e54 RunTest.done_u16918 +00:0e5a RunTest.done_u16920 +00:0e60 RunTest.done_u16922 +00:0e66 RunTest.done_u16924 +00:0e6c RunTest.done_u16926 +00:0e72 RunTest.done_u16928 +00:0e78 RunTest.done_u16930 +00:0edc RunTest.done_u16953 +00:0ee2 RunTest.done_u16955 +00:0ee8 RunTest.done_u16957 +00:0eee RunTest.done_u16959 +00:0ef4 RunTest.done_u16961 +00:0efa RunTest.done_u16963 +00:0f00 RunTest.done_u16965 +00:0f06 RunTest.done_u16967 +00:0f6d RunTest.done_u16991 +00:0f73 RunTest.done_u16993 +00:0f79 RunTest.done_u16995 +00:0f7f RunTest.done_u16997 +00:0f85 RunTest.done_u16999 +00:0f8b RunTest.done_u17001 +00:0f91 RunTest.done_u17003 +00:0f97 RunTest.done_u17005 +00:1001 RunTest.done_u17030 +00:1007 RunTest.done_u17032 +00:100d RunTest.done_u17034 +00:1013 RunTest.done_u17036 +00:1019 RunTest.done_u17038 +00:101f RunTest.done_u17040 +00:1025 RunTest.done_u17042 +00:102b RunTest.done_u17044 +00:1098 RunTest.done_u17070 +00:109e RunTest.done_u17072 +00:10a4 RunTest.done_u17074 +00:10aa RunTest.done_u17076 +00:10b0 RunTest.done_u17078 +00:10b6 RunTest.done_u17080 +00:10bc RunTest.done_u17082 +00:10c2 RunTest.done_u17084 +00:1132 RunTest.done_u17111 +00:1138 RunTest.done_u17113 +00:113e RunTest.done_u17115 +00:1144 RunTest.done_u17117 +00:114a RunTest.done_u17119 +00:1150 RunTest.done_u17121 +00:1156 RunTest.done_u17123 +00:115c RunTest.done_u17125 +00:11cf RunTest.done_u17153 +00:11d5 RunTest.done_u17155 +00:11db RunTest.done_u17157 +00:11e1 RunTest.done_u17159 +00:11e7 RunTest.done_u17161 +00:11ed RunTest.done_u17163 +00:11f3 RunTest.done_u17165 +00:11f9 RunTest.done_u17167 +00:126f RunTest.done_u17196 +00:1275 RunTest.done_u17198 +00:127b RunTest.done_u17200 +00:1281 RunTest.done_u17202 +00:1287 RunTest.done_u17204 +00:128d RunTest.done_u17206 +00:1293 RunTest.done_u17208 +00:1299 RunTest.done_u17210 +00:1312 RunTest.done_u17240 +00:1318 RunTest.done_u17242 +00:131e RunTest.done_u17244 +00:1324 RunTest.done_u17246 +00:132a RunTest.done_u17248 +00:1330 RunTest.done_u17250 +00:1336 RunTest.done_u17252 +00:133c RunTest.done_u17254 +00:13b8 RunTest.done_u17285 +00:13be RunTest.done_u17287 +00:13c4 RunTest.done_u17289 +00:13ca RunTest.done_u17291 +00:13d0 RunTest.done_u17293 +00:13d6 RunTest.done_u17295 +00:13dc RunTest.done_u17297 +00:13e2 RunTest.done_u17299 +00:1461 RunTest.done_u17331 +00:1467 RunTest.done_u17333 +00:146d RunTest.done_u17335 +00:1473 RunTest.done_u17337 +00:1479 RunTest.done_u17339 +00:147f RunTest.done_u17341 +00:1485 RunTest.done_u17343 +00:148b RunTest.done_u17345 +00:150d RunTest.done_u17378 +00:1513 RunTest.done_u17380 +00:1519 RunTest.done_u17382 +00:151f RunTest.done_u17384 +00:1525 RunTest.done_u17386 +00:152b RunTest.done_u17388 +00:1531 RunTest.done_u17390 +00:1537 RunTest.done_u17392 +00:15bc RunTest.done_u17426 +00:15c2 RunTest.done_u17428 +00:15c8 RunTest.done_u17430 +00:15ce RunTest.done_u17432 +00:15d4 RunTest.done_u17434 +00:15da RunTest.done_u17436 +00:15e0 RunTest.done_u17438 +00:15e6 RunTest.done_u17440 +00:15ea StoreResult +01:4000 NopSlide diff --git a/cinema/gb/samesuite/apu/div_write_trigger_volume_10/xbaseline_0000.png b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/xbaseline_0000.png new file mode 100644 index 000000000..5f5f952c1 Binary files /dev/null and b/cinema/gb/samesuite/apu/div_write_trigger_volume_10/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/config.ini b/cinema/gb/samesuite/config.ini new file mode 100644 index 000000000..6b38213c9 --- /dev/null +++ b/cinema/gb/samesuite/config.ini @@ -0,0 +1,6 @@ +[testinfo] +skip=60 +frames=1 + +[ports.cinema] +sgb.borders=0 diff --git a/cinema/gb/samesuite/dma/gbc_dma_cont/baseline_0000.png b/cinema/gb/samesuite/dma/gbc_dma_cont/baseline_0000.png new file mode 100644 index 000000000..b016da291 Binary files /dev/null and b/cinema/gb/samesuite/dma/gbc_dma_cont/baseline_0000.png differ diff --git a/cinema/gb/samesuite/dma/gbc_dma_cont/test.gb b/cinema/gb/samesuite/dma/gbc_dma_cont/test.gb new file mode 100644 index 000000000..15b9bc666 Binary files /dev/null and b/cinema/gb/samesuite/dma/gbc_dma_cont/test.gb differ diff --git a/cinema/gb/samesuite/dma/gbc_dma_cont/test.sym b/cinema/gb/samesuite/dma/gbc_dma_cont/test.sym new file mode 100644 index 000000000..a95387c7d --- /dev/null +++ b/cinema/gb/samesuite/dma/gbc_dma_cont/test.sym @@ -0,0 +1,47 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05db RunTest +00:05e8 RunTest.initTestBuf +00:05fb RunTest.initSrcBuf +01:4000 NopSlide +00:8800 vTestBuf +00:c000 SrcBuf diff --git a/cinema/gb/samesuite/dma/gdma_addr_mask/baseline_0000.png b/cinema/gb/samesuite/dma/gdma_addr_mask/baseline_0000.png new file mode 100644 index 000000000..367a0b27e Binary files /dev/null and b/cinema/gb/samesuite/dma/gdma_addr_mask/baseline_0000.png differ diff --git a/cinema/gb/samesuite/dma/gdma_addr_mask/test.gb b/cinema/gb/samesuite/dma/gdma_addr_mask/test.gb new file mode 100644 index 000000000..1180a5e34 Binary files /dev/null and b/cinema/gb/samesuite/dma/gdma_addr_mask/test.gb differ diff --git a/cinema/gb/samesuite/dma/gdma_addr_mask/test.sym b/cinema/gb/samesuite/dma/gdma_addr_mask/test.sym new file mode 100644 index 000000000..0e45f9371 --- /dev/null +++ b/cinema/gb/samesuite/dma/gdma_addr_mask/test.sym @@ -0,0 +1,48 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:05db RunTest.initTestBuf +00:05f0 RunTest.initSrcBuf +00:05fc RunTest.initHRAM +01:4000 NopSlide +00:8800 vTestBuf +00:c000 SrcBuf diff --git a/cinema/gb/samesuite/dma/hdma_lcd_off/config.ini b/cinema/gb/samesuite/dma/hdma_lcd_off/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/dma/hdma_lcd_off/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/dma/hdma_lcd_off/test.gb b/cinema/gb/samesuite/dma/hdma_lcd_off/test.gb new file mode 100644 index 000000000..04db06c83 Binary files /dev/null and b/cinema/gb/samesuite/dma/hdma_lcd_off/test.gb differ diff --git a/cinema/gb/samesuite/dma/hdma_lcd_off/test.sym b/cinema/gb/samesuite/dma/hdma_lcd_off/test.sym new file mode 100644 index 000000000..6e3b35efb --- /dev/null +++ b/cinema/gb/samesuite/dma/hdma_lcd_off/test.sym @@ -0,0 +1,48 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05d3 RunTest +00:05e1 RunTest.initTestBuf +00:05f4 RunTest.initSrcBuf +00:0600 RunTest.initHRAM +01:4000 NopSlide +00:8800 vTestBuf +00:c000 SrcBuf diff --git a/cinema/gb/samesuite/dma/hdma_lcd_off/xbaseline_0000.png b/cinema/gb/samesuite/dma/hdma_lcd_off/xbaseline_0000.png new file mode 100644 index 000000000..d1b4ff643 Binary files /dev/null and b/cinema/gb/samesuite/dma/hdma_lcd_off/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/dma/hdma_mode0/config.ini b/cinema/gb/samesuite/dma/hdma_mode0/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/dma/hdma_mode0/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/dma/hdma_mode0/test.gb b/cinema/gb/samesuite/dma/hdma_mode0/test.gb new file mode 100644 index 000000000..cb7df3705 Binary files /dev/null and b/cinema/gb/samesuite/dma/hdma_mode0/test.gb differ diff --git a/cinema/gb/samesuite/dma/hdma_mode0/test.sym b/cinema/gb/samesuite/dma/hdma_mode0/test.sym new file mode 100644 index 000000000..6e3b35efb --- /dev/null +++ b/cinema/gb/samesuite/dma/hdma_mode0/test.sym @@ -0,0 +1,48 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05d3 RunTest +00:05e1 RunTest.initTestBuf +00:05f4 RunTest.initSrcBuf +00:0600 RunTest.initHRAM +01:4000 NopSlide +00:8800 vTestBuf +00:c000 SrcBuf diff --git a/cinema/gb/samesuite/dma/hdma_mode0/xbaseline_0000.png b/cinema/gb/samesuite/dma/hdma_mode0/xbaseline_0000.png new file mode 100644 index 000000000..d1b4ff643 Binary files /dev/null and b/cinema/gb/samesuite/dma/hdma_mode0/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/interrupt/ei_delay_halt/config.ini b/cinema/gb/samesuite/interrupt/ei_delay_halt/config.ini new file mode 100644 index 000000000..7ddee425b --- /dev/null +++ b/cinema/gb/samesuite/interrupt/ei_delay_halt/config.ini @@ -0,0 +1,2 @@ +[testinfo] +fail=1 diff --git a/cinema/gb/samesuite/interrupt/ei_delay_halt/test.gb b/cinema/gb/samesuite/interrupt/ei_delay_halt/test.gb new file mode 100644 index 000000000..22d67738c Binary files /dev/null and b/cinema/gb/samesuite/interrupt/ei_delay_halt/test.gb differ diff --git a/cinema/gb/samesuite/interrupt/ei_delay_halt/test.sym b/cinema/gb/samesuite/interrupt/ei_delay_halt/test.sym new file mode 100644 index 000000000..57b57266c --- /dev/null +++ b/cinema/gb/samesuite/interrupt/ei_delay_halt/test.sym @@ -0,0 +1,47 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05cb RunTest +00:0604 RunTest.halt +01:4000 NopSlide +00:c000 RESULTS_START +00:c020 RESULTS_START.end +00:c020 wSPSave diff --git a/cinema/gb/samesuite/interrupt/ei_delay_halt/xbaseline_0000.png b/cinema/gb/samesuite/interrupt/ei_delay_halt/xbaseline_0000.png new file mode 100644 index 000000000..e8ff40eb1 Binary files /dev/null and b/cinema/gb/samesuite/interrupt/ei_delay_halt/xbaseline_0000.png differ diff --git a/cinema/gb/samesuite/ppu/blocking_bgpi_increase/baseline_0000.png b/cinema/gb/samesuite/ppu/blocking_bgpi_increase/baseline_0000.png new file mode 100644 index 000000000..86ad2e3f7 Binary files /dev/null and b/cinema/gb/samesuite/ppu/blocking_bgpi_increase/baseline_0000.png differ diff --git a/cinema/gb/samesuite/ppu/blocking_bgpi_increase/test.gb b/cinema/gb/samesuite/ppu/blocking_bgpi_increase/test.gb new file mode 100644 index 000000000..862260c53 Binary files /dev/null and b/cinema/gb/samesuite/ppu/blocking_bgpi_increase/test.gb differ diff --git a/cinema/gb/samesuite/ppu/blocking_bgpi_increase/test.sym b/cinema/gb/samesuite/ppu/blocking_bgpi_increase/test.sym new file mode 100644 index 000000000..d9a1dee8e --- /dev/null +++ b/cinema/gb/samesuite/ppu/blocking_bgpi_increase/test.sym @@ -0,0 +1,48 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:05d0 RunTest.waitWrite_u16402 +00:05e1 RunTest.waitWrite_u16403 +00:05f2 RunTest.waitWrite_u16404 +00:0605 RunTest.delay_u16405 +00:0609 RunTest.waitWrite_u16405 +01:4000 NopSlide diff --git a/cinema/gb/samesuite/sgb/command_mlt_req/baseline_0000.png b/cinema/gb/samesuite/sgb/command_mlt_req/baseline_0000.png new file mode 100644 index 000000000..602e3026a Binary files /dev/null and b/cinema/gb/samesuite/sgb/command_mlt_req/baseline_0000.png differ diff --git a/cinema/gb/samesuite/sgb/command_mlt_req/test.gb b/cinema/gb/samesuite/sgb/command_mlt_req/test.gb new file mode 100644 index 000000000..8d8b9514b Binary files /dev/null and b/cinema/gb/samesuite/sgb/command_mlt_req/test.gb differ diff --git a/cinema/gb/samesuite/sgb/command_mlt_req/test.sym b/cinema/gb/samesuite/sgb/command_mlt_req/test.sym new file mode 100644 index 000000000..8e0961ba3 --- /dev/null +++ b/cinema/gb/samesuite/sgb/command_mlt_req/test.sym @@ -0,0 +1,55 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05c3 RunTest +00:07e2 SendSgbPacket +00:07ed SendSgbPacket.sgbByte +00:07f1 SendSgbPacket.sgbByteLoop +00:07f9 SendSgbPacket.sgbBit +00:0811 SgbWait +00:0815 SgbWait.waitloop +00:081f Increment +00:0828 StoreResult +00:082b MLT_REQ_0 +00:083b MLT_REQ_1 +00:084b MLT_REQ_2 +00:085b MLT_REQ_3 +01:4000 NopSlide diff --git a/cinema/gb/samesuite/sgb/command_mlt_req_1/baseline_0000.png b/cinema/gb/samesuite/sgb/command_mlt_req_1/baseline_0000.png new file mode 100644 index 000000000..602e3026a Binary files /dev/null and b/cinema/gb/samesuite/sgb/command_mlt_req_1/baseline_0000.png differ diff --git a/cinema/gb/samesuite/sgb/command_mlt_req_1/test.gb b/cinema/gb/samesuite/sgb/command_mlt_req_1/test.gb new file mode 100644 index 000000000..3b4f846f1 Binary files /dev/null and b/cinema/gb/samesuite/sgb/command_mlt_req_1/test.gb differ diff --git a/cinema/gb/samesuite/sgb/command_mlt_req_1/test.sym b/cinema/gb/samesuite/sgb/command_mlt_req_1/test.sym new file mode 100644 index 000000000..8a6eef44c --- /dev/null +++ b/cinema/gb/samesuite/sgb/command_mlt_req_1/test.sym @@ -0,0 +1,50 @@ +; File generated by rgblink + +00:0100 Start +00:04C3 _Start +00:0163 LCDOff.ret +00:0157 LCDOff.LCDOffLoop +00:01A1 HexDigits +00:0176 LoadFont.loop +00:017C LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:03B7 LoadPalettes +00:03BC LoadPalettes.loop +00:0150 LCDOff +00:016E LoadFont +00:03A1 Palette +00:03B5 LoadBGPalettes +00:03B1 LoadObjPalettes +00:03F9 ModemCh1Freqs +00:0409 ModemCh2Freqs +00:0419 ModemCh3Freqs +00:03E0 ModemSleep +00:0429 ModemSendByte +00:04BB ModemSendBuffer +00:03C2 CommonInit +00:05B4 RunTest +00:0523 PrintResults +00:0165 LCDOn +00:04DF _Start.loop_16399 +00:04FA _Start.failed +00:0501 _Start.sendSerial +00:0597 SerialSendByte +00:0519 _Start.loop_16400 +00:05A4 CorrectResults +00:0562 PrintResults.correct +00:0576 PrintResults.correct2 +00:0550 PrintResults.xLoop +00:052C PrintResults.yLoop +00:059D SerialSendByte.loop +00:0715 MLT_REQ_1 +00:06BC SendSgbPacket +00:0702 StoreResult +00:06F9 Increment +00:0705 MLT_REQ_0 +00:0725 MLT_REQ_2 +00:0735 MLT_REQ_3 +00:06D3 SendSgbPacket.sgbBit +00:06CB SendSgbPacket.sgbByteLoop +00:06C7 SendSgbPacket.sgbByte +00:06EF SgbWait.waitloop diff --git a/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/baseline_0000.png b/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/baseline_0000.png new file mode 100644 index 000000000..111d30360 Binary files /dev/null and b/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/baseline_0000.png differ diff --git a/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/test.gb b/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/test.gb new file mode 100644 index 000000000..bd1aef6c9 Binary files /dev/null and b/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/test.gb differ diff --git a/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/test.sym b/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/test.sym new file mode 100644 index 000000000..9d0a8fb79 --- /dev/null +++ b/cinema/gb/samesuite/sgb/command_mlt_req_1_incrementing/test.sym @@ -0,0 +1,52 @@ +; File generated by rgblink +00:00ff reboot +00:0100 Start +00:0150 LCDOff +00:0157 LCDOff.LCDOffLoop +00:0163 LCDOff.ret +00:0165 LCDOn +00:016e LoadFont +00:0176 LoadFont.loop +00:017c LoadFont.loop2 +00:0185 LoadFont.loop3 +00:0192 LoadFont.loop4 +00:01a1 HexDigits +00:03a1 Palette +00:03b1 LoadObjPalettes +00:03b5 LoadBGPalettes +00:03b7 LoadPalettes +00:03bc LoadPalettes.loop +00:03c2 CommonInit +00:03d0 CommonInit.clearLogoTilemap +00:03e9 ModemSleep +00:0401 ModemCh1Freqs +00:0411 ModemCh2Freqs +00:0421 ModemCh3Freqs +00:0431 ModemSendByte +00:0485 ModemStart +00:04bf ModemStop +00:04c3 ModemSendBuffer +00:04cb _Start +00:04e7 _Start.loop_u16400 +00:0502 _Start.failed +00:0509 _Start.sendSerial +00:0521 _Start.loop_u16401 +00:052a PrintResults +00:0533 PrintResults.yLoop +00:0557 PrintResults.xLoop +00:0569 PrintResults.correct +00:057d PrintResults.correct2 +00:059e SerialSendByte +00:05a4 SerialSendByte.loop +00:05ab CorrectResults +00:05b3 RunTest +00:063c SendSgbPacket +00:0647 SendSgbPacket.sgbByte +00:064b SendSgbPacket.sgbByteLoop +00:0653 SendSgbPacket.sgbBit +00:066b SgbWait +00:066f SgbWait.waitloop +00:0679 StoreResult +00:067c MLT_REQ_0 +00:068c MLT_REQ_1 +01:4000 NopSlide diff --git a/include/mgba-util/common.h b/include/mgba-util/common.h index 2cd8dcd6d..9625d3d90 100644 --- a/include/mgba-util/common.h +++ b/include/mgba-util/common.h @@ -44,6 +44,10 @@ CXX_GUARD_START #define restrict __restrict #endif +#ifndef containerof +#define containerof(PTR, TYPE, MEMBER) ((TYPE*) ((uintptr_t) (PTR) - offsetof(TYPE, MEMBER))) +#endif + #ifdef _MSC_VER #include #include @@ -112,13 +116,13 @@ typedef intptr_t ssize_t; #define ATOMIC_LOAD_PTR(DST, SRC) DST = InterlockedCompareExchangePointer(&SRC, 0, 0) #else /* TODO */ -#define ATOMIC_STORE(DST, SRC) DST = SRC -#define ATOMIC_LOAD(DST, SRC) DST = SRC -#define ATOMIC_ADD(DST, OP) DST += OP -#define ATOMIC_SUB(DST, OP) DST -= OP -#define ATOMIC_OR(DST, OP) DST |= OP -#define ATOMIC_AND(DST, OP) DST &= OP -#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false) +#define ATOMIC_STORE(DST, SRC) ((DST) = (SRC)) +#define ATOMIC_LOAD(DST, SRC) ((DST) = (SRC)) +#define ATOMIC_ADD(DST, OP) ((DST) += (OP)) +#define ATOMIC_SUB(DST, OP) ((DST) -= (OP)) +#define ATOMIC_OR(DST, OP) ((DST) |= (OP)) +#define ATOMIC_AND(DST, OP) ((DST) &= (OP)) +#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) (((DST) == (EXPECTED)) ? (((DST) = (OP)), true) : false) #define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC) #define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC) #endif diff --git a/include/mgba-util/geometry.h b/include/mgba-util/geometry.h new file mode 100644 index 000000000..aa7d65e94 --- /dev/null +++ b/include/mgba-util/geometry.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef GEOMETRY_H +#define GEOMETRY_H + +#include + +CXX_GUARD_START + +struct mSize { + int width; + int height; +}; + +struct mRectangle { + int x; + int y; + int width; + int height; +}; + +void mRectangleUnion(struct mRectangle* dst, const struct mRectangle* add); +bool mRectangleIntersection(struct mRectangle* dst, const struct mRectangle* add); +void mRectangleCenter(const struct mRectangle* ref, struct mRectangle* rect); + +CXX_GUARD_END + +#endif diff --git a/include/mgba-util/gui/font-metrics.h b/include/mgba-util/gui/font-metrics.h index c60d6dfc8..c2e6668d4 100644 --- a/include/mgba-util/gui/font-metrics.h +++ b/include/mgba-util/gui/font-metrics.h @@ -6,9 +6,10 @@ #ifndef DEFAULT_FONT_METRICS_H #define DEFAULT_FONT_METRICS_H +#include #include -extern struct GUIFontGlyphMetric defaultFontMetrics[]; -extern struct GUIIconMetric defaultIconMetrics[]; +extern const struct GUIFontGlyphMetric defaultFontMetrics[128]; +extern const struct GUIIconMetric defaultIconMetrics[GUI_ICON_MAX]; #endif diff --git a/include/mgba-util/image.h b/include/mgba-util/image.h new file mode 100644 index 000000000..31514687d --- /dev/null +++ b/include/mgba-util/image.h @@ -0,0 +1,397 @@ +/* Copyright (c) 2013-2015 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/. */ +#ifndef M_IMAGE_H +#define M_IMAGE_H + +#include + +CXX_GUARD_START + +#ifdef COLOR_16_BIT +typedef uint16_t color_t; +#define BYTES_PER_PIXEL 2 +#else +typedef uint32_t color_t; +#define BYTES_PER_PIXEL 4 +#endif + +#define M_R5(X) ((X) & 0x1F) +#define M_G5(X) (((X) >> 5) & 0x1F) +#define M_B5(X) (((X) >> 10) & 0x1F) + +#define M_R8(X) ((M_R5(X) * 0x21) >> 2) +#define M_G8(X) ((M_G5(X) * 0x21) >> 2) +#define M_B8(X) ((M_B5(X) * 0x21) >> 2) + +#define M_RGB5_TO_BGR8(X) ((M_R5(X) << 3) | (M_G5(X) << 11) | (M_B5(X) << 19)) +#define M_RGB5_TO_RGB8(X) ((M_R5(X) << 19) | (M_G5(X) << 11) | (M_B5(X) << 3)) +#define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9)) +#define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19)) + +#ifndef COLOR_16_BIT +#define M_COLOR_RED 0x000000FF +#define M_COLOR_GREEN 0x0000FF00 +#define M_COLOR_BLUE 0x00FF0000 +#define M_COLOR_ALPHA 0xFF000000 +#define M_COLOR_WHITE 0x00FFFFFF + +#define M_RGB8_TO_NATIVE(X) (((X) & 0x00FF00) | (((X) & 0x0000FF) << 16) | (((X) & 0xFF0000) >> 16)) +#elif defined(COLOR_5_6_5) +#define M_COLOR_RED 0x001F +#define M_COLOR_GREEN 0x07E0 +#define M_COLOR_BLUE 0xF800 +#define M_COLOR_ALPHA 0x0000 +#define M_COLOR_WHITE 0xFFDF + +#define M_RGB8_TO_NATIVE(X) ((((X) & 0xF8) << 8) | (((X) & 0xFC00) >> 5) | (((X) & 0xF80000) >> 19)) +#else +#define M_COLOR_RED 0x001F +#define M_COLOR_GREEN 0x03E0 +#define M_COLOR_BLUE 0x7C00 +#define M_COLOR_ALPHA 0x1000 +#define M_COLOR_WHITE 0x7FFF + +#define M_RGB8_TO_NATIVE(X) M_RGB8_TO_BGR5(X) +#endif + +enum mColorFormat { + mCOLOR_XBGR8 = 0x00001, + mCOLOR_XRGB8 = 0x00002, + mCOLOR_BGRX8 = 0x00004, + mCOLOR_RGBX8 = 0x00008, + mCOLOR_ABGR8 = 0x00010, + mCOLOR_ARGB8 = 0x00020, + mCOLOR_BGRA8 = 0x00040, + mCOLOR_RGBA8 = 0x00080, + mCOLOR_RGB5 = 0x00100, + mCOLOR_BGR5 = 0x00200, + mCOLOR_RGB565 = 0x00400, + mCOLOR_BGR565 = 0x00800, + mCOLOR_ARGB5 = 0x01000, + mCOLOR_ABGR5 = 0x02000, + mCOLOR_RGBA5 = 0x04000, + mCOLOR_BGRA5 = 0x08000, + mCOLOR_RGB8 = 0x10000, + mCOLOR_BGR8 = 0x20000, + mCOLOR_L8 = 0x40000, + mCOLOR_PAL8 = 0x80000, + + mCOLOR_ANY = -1 +}; + +#ifndef COLOR_16_BIT +#define mCOLOR_NATIVE mCOLOR_XBGR8 +#elif !defined(COLOR_5_6_5) +#define mCOLOR_NATIVE mCOLOR_BGR5 +#else +#define mCOLOR_NATIVE mCOLOR_RGB565 +#endif + +struct mImage { + void* data; + uint32_t* palette; + unsigned width; + unsigned height; + unsigned stride; + unsigned depth; + unsigned palSize; + enum mColorFormat format; +}; + +struct mPainter { + struct mImage* backing; + bool blend; + bool fill; + unsigned strokeWidth; + uint32_t strokeColor; + uint32_t fillColor; +}; + +struct VFile; +struct mImage* mImageCreate(unsigned width, unsigned height, enum mColorFormat format); +struct mImage* mImageCreateWithStride(unsigned width, unsigned height, unsigned stride, enum mColorFormat format); +struct mImage* mImageCreateFromConstBuffer(unsigned width, unsigned height, unsigned stride, enum mColorFormat format, const void* pixels); +struct mImage* mImageLoad(const char* path); +struct mImage* mImageLoadVF(struct VFile* vf); +struct mImage* mImageConvertToFormat(const struct mImage*, enum mColorFormat format); +void mImageDestroy(struct mImage*); + +bool mImageSave(const struct mImage*, const char* path, const char* format); +bool mImageSaveVF(const struct mImage*, struct VFile* vf, const char* format); + +uint32_t mImageGetPixel(const struct mImage* image, unsigned x, unsigned y); +uint32_t mImageGetPixelRaw(const struct mImage* image, unsigned x, unsigned y); +void mImageSetPixel(struct mImage* image, unsigned x, unsigned y, uint32_t color); +void mImageSetPixelRaw(struct mImage* image, unsigned x, unsigned y, uint32_t color); + +void mImageSetPaletteSize(struct mImage* image, unsigned count); +void mImageSetPaletteEntry(struct mImage* image, unsigned index, uint32_t color); + +void mImageBlit(struct mImage* image, const struct mImage* source, int x, int y); +void mImageComposite(struct mImage* image, const struct mImage* source, int x, int y); +void mImageCompositeWithAlpha(struct mImage* image, const struct mImage* source, int x, int y, float alpha); + +void mPainterInit(struct mPainter*, struct mImage* backing); +void mPainterDrawRectangle(struct mPainter*, int x, int y, int width, int height); +void mPainterDrawLine(struct mPainter*, int x1, int y1, int x2, int y2); +void mPainterDrawCircle(struct mPainter*, int x, int y, int diameter); + +uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to); +uint32_t mImageColorConvert(uint32_t color, const struct mImage* from, enum mColorFormat to); + +#ifndef PYCPARSE +static inline unsigned mColorFormatBytes(enum mColorFormat format) { + switch (format) { + case mCOLOR_XBGR8: + case mCOLOR_XRGB8: + case mCOLOR_BGRX8: + case mCOLOR_RGBX8: + case mCOLOR_ABGR8: + case mCOLOR_ARGB8: + case mCOLOR_BGRA8: + case mCOLOR_RGBA8: + return 4; + case mCOLOR_RGB5: + case mCOLOR_BGR5: + case mCOLOR_RGB565: + case mCOLOR_BGR565: + case mCOLOR_ARGB5: + case mCOLOR_ABGR5: + case mCOLOR_RGBA5: + case mCOLOR_BGRA5: + return 2; + case mCOLOR_RGB8: + case mCOLOR_BGR8: + return 3; + case mCOLOR_L8: + case mCOLOR_PAL8: + return 1; + case mCOLOR_ANY: + break; + } + return 0; +} + +static inline bool mColorFormatHasAlpha(enum mColorFormat format) { + switch (format) { + case mCOLOR_XBGR8: + case mCOLOR_XRGB8: + case mCOLOR_BGRX8: + case mCOLOR_RGBX8: + case mCOLOR_RGB5: + case mCOLOR_BGR5: + case mCOLOR_RGB565: + case mCOLOR_BGR565: + case mCOLOR_RGB8: + case mCOLOR_BGR8: + case mCOLOR_L8: + return false; + case mCOLOR_ABGR8: + case mCOLOR_ARGB8: + case mCOLOR_BGRA8: + case mCOLOR_RGBA8: + case mCOLOR_ARGB5: + case mCOLOR_ABGR5: + case mCOLOR_RGBA5: + case mCOLOR_BGRA5: + case mCOLOR_PAL8: + return true; + case mCOLOR_ANY: + break; + } + return false; +} + +static inline color_t mColorFrom555(uint16_t value) { +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + color_t color = 0; + color |= (value & 0x001F) << 11; + color |= (value & 0x03E0) << 1; + color |= (value & 0x7C00) >> 10; +#else + color_t color = value; +#endif +#else + color_t color = M_RGB5_TO_BGR8(value); + color |= (color >> 5) & 0x070707; +#endif + return color; +} + +ATTRIBUTE_UNUSED static unsigned mColorMix5Bit(int weightA, unsigned colorA, int weightB, unsigned colorB) { + unsigned c = 0; + unsigned a, b; +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + a = colorA & 0xF81F; + b = colorB & 0xF81F; + a |= (colorA & 0x7C0) << 16; + b |= (colorB & 0x7C0) << 16; + c = ((a * weightA + b * weightB) / 16); + if (c & 0x08000000) { + c = (c & ~0x0FC00000) | 0x07C00000; + } + if (c & 0x0020) { + c = (c & ~0x003F) | 0x001F; + } + if (c & 0x10000) { + c = (c & ~0x1F800) | 0xF800; + } + c = (c & 0xF81F) | ((c >> 16) & 0x07C0); +#else + a = colorA & 0x7C1F; + b = colorB & 0x7C1F; + a |= (colorA & 0x3E0) << 16; + b |= (colorB & 0x3E0) << 16; + c = ((a * weightA + b * weightB) / 16); + if (c & 0x04000000) { + c = (c & ~0x07E00000) | 0x03E00000; + } + if (c & 0x0020) { + c = (c & ~0x003F) | 0x001F; + } + if (c & 0x8000) { + c = (c & ~0xF800) | 0x7C00; + } + c = (c & 0x7C1F) | ((c >> 16) & 0x03E0); +#endif +#else + a = colorA & 0xFF; + b = colorB & 0xFF; + c |= ((a * weightA + b * weightB) / 16) & 0x1FF; + if (c & 0x00000100) { + c = 0x000000FF; + } + + a = colorA & 0xFF00; + b = colorB & 0xFF00; + c |= ((a * weightA + b * weightB) / 16) & 0x1FF00; + if (c & 0x00010000) { + c = (c & 0x000000FF) | 0x0000FF00; + } + + a = colorA & 0xFF0000; + b = colorB & 0xFF0000; + c |= ((a * weightA + b * weightB) / 16) & 0x1FF0000; + if (c & 0x01000000) { + c = (c & 0x0000FFFF) | 0x00FF0000; + } +#endif + return c; +} + +ATTRIBUTE_UNUSED static uint32_t mColorMixARGB8(uint32_t colorA, uint32_t colorB) { + uint32_t alphaA = colorA >> 24; + if (!alphaA) { + return colorB; + } + uint32_t alphaB = colorB >> 24; + uint32_t color = 0; + +#if 1 + // TODO: Benchmark integer and float versions + uint32_t a, b; + uint32_t alpha = (alphaA * 0xFF) + alphaB * (0xFF - alphaA); + + a = colorA & 0xFF; + a *= alphaA * 0xFF; + b = a; + + a = colorB & 0xFF; + a *= alphaB * (0xFF - alphaA); + b += a; + + b /= alpha; + if (b > 0xFF) { + color |= 0xFF; + } else { + color |= b; + } + + a = (colorA >> 8) & 0xFF; + a *= alphaA * 0xFF; + b = a; + + a = (colorB >> 8) & 0xFF; + a *= alphaB * (0xFF - alphaA); + b += a; + + b /= alpha; + if (b > 0xFF) { + color |= 0xFF00; + } else { + color |= b << 8; + } + + a = (colorA >> 16) & 0xFF; + a *= alphaA * 0xFF; + b = a; + + a = (colorB >> 16) & 0xFF; + a *= alphaB * (0xFF - alphaA); + b += a; + + b /= alpha; + if (b > 0xFF) { + color |= 0xFF0000; + } else { + color |= b << 16; + } + + alpha /= 0xFF; + if (alpha > 0xFF) { + color |= 0xFF000000; + } else { + color |= alpha << 24; + } +#else + float ca, aa; + float cb, ab; + + static const float r255 = 1 / 255.f; + aa = alphaA * r255; + ab = alphaB * r255; + float alpha = aa + ab * (1.f - aa); + float ralpha = 1.f / alpha; + alpha = alpha * 255.f; + color = ((int) alpha) << 24; + + ca = ((colorA >> 16) & 0xFF) * r255; + cb = ((colorB >> 16) & 0xFF) * r255; + ca = ca * aa + cb * ab * (1.f - aa); + ca = ca * ralpha * 255.f; + if (ca > 255.f) { + ca = 255.f; + } + color |= ((int) ca) << 16; + + ca = ((colorA >> 8) & 0xFF) * r255; + cb = ((colorB >> 8) & 0xFF) * r255; + ca = ca * aa + cb * ab * (1.f - aa); + ca = ca * ralpha * 255.f; + if (ca > 255.f) { + ca = 255.f; + } + color |= ((int) ca) << 8; + + ca = (colorA & 0xFF) * r255; + cb = (colorB & 0xFF) * r255; + ca = ca * aa + cb * ab * (1.f - aa); + ca = ca * ralpha * 255.f; + if (ca > 255.f) { + ca = 255.f; + } + color |= (int) ca; +#endif + + return color; +} +#endif + +CXX_GUARD_END + +#endif diff --git a/include/mgba-util/export.h b/include/mgba-util/image/export.h similarity index 56% rename from include/mgba-util/export.h rename to include/mgba-util/image/export.h index 92047b93b..bc657cb87 100644 --- a/include/mgba-util/export.h +++ b/include/mgba-util/image/export.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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/. */ -#ifndef EXPORT_H -#define EXPORT_H +#ifndef M_IMAGE_EXPORT_H +#define M_IMAGE_EXPORT_H #include @@ -12,8 +12,8 @@ CXX_GUARD_START struct VFile; -bool exportPaletteRIFF(struct VFile* vf, size_t entries, const uint16_t* colors); -bool exportPaletteACT(struct VFile* vf, size_t entries, const uint16_t* colors); +bool mPaletteExportRIFF(struct VFile* vf, size_t entries, const uint16_t* colors); +bool mPaletteExportACT(struct VFile* vf, size_t entries, const uint16_t* colors); CXX_GUARD_END diff --git a/include/mgba-util/png-io.h b/include/mgba-util/image/png-io.h similarity index 76% rename from include/mgba-util/png-io.h rename to include/mgba-util/image/png-io.h index 4156b5d20..b9b82c0ac 100644 --- a/include/mgba-util/png-io.h +++ b/include/mgba-util/image/png-io.h @@ -12,6 +12,8 @@ CXX_GUARD_START #ifdef USE_PNG +#include + // png.h defines its own version of restrict which conflicts with mGBA's. #ifdef restrict #undef restrict @@ -25,13 +27,10 @@ enum { }; png_structp PNGWriteOpen(struct VFile* source); -png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height); -png_infop PNGWriteHeaderA(png_structp png, unsigned width, unsigned height); -png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height); -bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries); -bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); -bool PNGWritePixelsA(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); -bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); +png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height, enum mColorFormat); +png_infop PNGWriteHeaderPalette(png_structp png, unsigned width, unsigned height, const uint32_t* palette, unsigned entries); +bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels, enum mColorFormat); +bool PNGWritePixelsPalette(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data); void PNGWriteClose(png_structp png, png_infop info); diff --git a/include/mgba-util/macros.h b/include/mgba-util/macros.h index f994def47..904c15274 100644 --- a/include/mgba-util/macros.h +++ b/include/mgba-util/macros.h @@ -9,6 +9,7 @@ #define _mCPP_CAT(A, B) A ## B #define _mIDENT(...) __VA_ARGS__ +#define _mVOID(...) #define _mCALL(FN, ...) _mIDENT(FN(__VA_ARGS__)) #define _mCAT(A, B) _mCPP_CAT(A, B) #define _mSTRINGIFY(X, ...) #X @@ -16,13 +17,13 @@ #define _mCALL_0(FN, ...) #define _mCALL_1(FN, A) FN(A) #define _mCALL_2(FN, A, B) FN(A), FN(B) -#define _mCALL_3(FN, A, ...) FN(A), _mCALL_2(FN, __VA_ARGS__) -#define _mCALL_4(FN, A, ...) FN(A), _mCALL_3(FN, __VA_ARGS__) -#define _mCALL_5(FN, A, ...) FN(A), _mCALL_4(FN, __VA_ARGS__) -#define _mCALL_6(FN, A, ...) FN(A), _mCALL_5(FN, __VA_ARGS__) -#define _mCALL_7(FN, A, ...) FN(A), _mCALL_6(FN, __VA_ARGS__) -#define _mCALL_8(FN, A, ...) FN(A), _mCALL_7(FN, __VA_ARGS__) -#define _mCALL_9(FN, A, ...) FN(A), _mCALL_8(FN, __VA_ARGS__) +#define _mCALL_3(FN, A, B, C) FN(A), FN(B), FN(C) +#define _mCALL_4(FN, A, B, C, D) FN(A), FN(B), FN(C), FN(D) +#define _mCALL_5(FN, A, B, C, D, E) FN(A), FN(B), FN(C), FN(D), FN(E) +#define _mCALL_6(FN, A, B, C, D, E, F) FN(A), FN(B), FN(C), FN(D), FN(E), FN(F) +#define _mCALL_7(FN, A, B, C, D, E, F, G) FN(A), FN(B), FN(C), FN(D), FN(E), FN(F), FN(G) +#define _mCALL_8(FN, A, B, C, D, E, F, G, H) FN(A), FN(B), FN(C), FN(D), FN(E), FN(F), FN(G), FN(H) +#define _mCALL_9(FN, A, B, C, D, E, F, G, H, I) FN(A), FN(B), FN(C), FN(D), FN(E), FN(F), FN(G), FN(H), FN(I) #define _mCOMMA_0(N, ...) N #define _mCOMMA_1(N, ...) N, __VA_ARGS__ @@ -37,25 +38,25 @@ #define _mEVEN_0(...) #define _mEVEN_1(A, B, ...) A -#define _mEVEN_2(A, B, ...) A, _mIDENT(_mEVEN_1(__VA_ARGS__)) -#define _mEVEN_3(A, B, ...) A, _mIDENT(_mEVEN_2(__VA_ARGS__)) -#define _mEVEN_4(A, B, ...) A, _mIDENT(_mEVEN_3(__VA_ARGS__)) -#define _mEVEN_5(A, B, ...) A, _mIDENT(_mEVEN_4(__VA_ARGS__)) +#define _mEVEN_2(A, B, C, D, ...) A, C +#define _mEVEN_3(A, B, C, D, E, F, ...) A, C, E +#define _mEVEN_4(A, B, C, D, E, F, G, H, ...) A, C, E, G +#define _mEVEN_5(A, B, C, D, E, F, G, H, I, J, ...) A, C, E, G, I #define _mEVEN_6(A, B, ...) A, _mIDENT(_mEVEN_5(__VA_ARGS__)) -#define _mEVEN_7(A, B, ...) A, _mIDENT(_mEVEN_6(__VA_ARGS__)) -#define _mEVEN_8(A, B, ...) A, _mIDENT(_mEVEN_7(__VA_ARGS__)) -#define _mEVEN_9(A, B, ...) A, _mIDENT(_mEVEN_7(__VA_ARGS__)) +#define _mEVEN_7(A, B, C, D, ...) A, C, _mIDENT(_mEVEN_5(__VA_ARGS__)) +#define _mEVEN_8(A, B, C, D, E, F, ...) A, C, E, _mIDENT(_mEVEN_5(__VA_ARGS__)) +#define _mEVEN_9(A, B, C, D, E, F, G, H, ...) A, C, E, G, _mIDENT(_mEVEN_5(__VA_ARGS__)) #define _mODD_0(...) #define _mODD_1(A, B, ...) B -#define _mODD_2(A, B, ...) B, _mIDENT(_mODD_1(__VA_ARGS__)) -#define _mODD_3(A, B, ...) B, _mIDENT(_mODD_2(__VA_ARGS__)) -#define _mODD_4(A, B, ...) B, _mIDENT(_mODD_3(__VA_ARGS__)) -#define _mODD_5(A, B, ...) B, _mIDENT(_mODD_4(__VA_ARGS__)) +#define _mODD_2(A, B, C, D, ...) B, D +#define _mODD_3(A, B, C, D, E, F, ...) B, D, F +#define _mODD_4(A, B, C, D, E, F, G, H, ...) B, D, F, H +#define _mODD_5(A, B, C, D, E, F, G, H, I, J, ...) B, D, F, H, J #define _mODD_6(A, B, ...) B, _mIDENT(_mODD_5(__VA_ARGS__)) -#define _mODD_7(A, B, ...) B, _mIDENT(_mODD_6(__VA_ARGS__)) -#define _mODD_8(A, B, ...) B, _mIDENT(_mODD_7(__VA_ARGS__)) -#define _mODD_9(A, B, ...) B, _mIDENT(_mODD_7(__VA_ARGS__)) +#define _mODD_7(A, B, C, D, ...) B, D, _mIDENT(_mODD_5(__VA_ARGS__)) +#define _mODD_8(A, B, C, D, E, F, ...) B, D, F, _mIDENT(_mODD_5(__VA_ARGS__)) +#define _mODD_9(A, B, C, D, E, F, G, H, ...) B, D, F, H, _mIDENT(_mODD_5(__VA_ARGS__)) #define _mIF0_0(...) __VA_ARGS__ #define _mIF0_1(...) diff --git a/include/mgba-util/math.h b/include/mgba-util/math.h index 66cdae885..a9cba9824 100644 --- a/include/mgba-util/math.h +++ b/include/mgba-util/math.h @@ -25,7 +25,7 @@ static inline unsigned clz32(uint32_t bits) { } return __builtin_clz(bits); #else - static const int table[256] = { + static const int8_t table[256] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -55,6 +55,43 @@ static inline unsigned clz32(uint32_t bits) { #endif } +static inline unsigned ctz32(uint32_t bits) { +#if defined(__GNUC__) || __clang__ + if (!bits) { + return 32; + } + return __builtin_ctz(bits); +#else + static const int8_t table[256] = { + 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + }; + + if (bits & 0x000000FF) { + return table[bits & 0xFF]; + } else if (bits & 0x0000FF00) { + return table[(bits >> 8) & 0xFF] + 8; + } else if (bits & 0x00FF0000) { + return table[(bits >> 16) & 0xFF] + 16; + } + return table[bits >> 24] + 24; +#endif +} + static inline uint32_t toPow2(uint32_t bits) { if (!bits) { return 0; diff --git a/include/mgba-util/platform/3ds/threading.h b/include/mgba-util/platform/3ds/threading.h index dfc03342d..8d5555317 100644 --- a/include/mgba-util/platform/3ds/threading.h +++ b/include/mgba-util/platform/3ds/threading.h @@ -12,6 +12,7 @@ #include #define THREAD_ENTRY void +#define THREAD_EXIT(RES) return typedef ThreadFunc ThreadEntry; typedef LightLock Mutex; diff --git a/include/mgba-util/platform/posix/threading.h b/include/mgba-util/platform/posix/threading.h index c8d42ed73..ad6e99690 100644 --- a/include/mgba-util/platform/posix/threading.h +++ b/include/mgba-util/platform/posix/threading.h @@ -20,6 +20,7 @@ CXX_GUARD_START #define THREAD_ENTRY void* typedef THREAD_ENTRY (*ThreadEntry)(void*); +#define THREAD_EXIT(RES) return RES typedef pthread_t Thread; typedef pthread_mutex_t Mutex; diff --git a/include/mgba-util/platform/psp2/threading.h b/include/mgba-util/platform/psp2/threading.h index ba4827229..4c084804c 100644 --- a/include/mgba-util/platform/psp2/threading.h +++ b/include/mgba-util/platform/psp2/threading.h @@ -17,6 +17,7 @@ typedef struct { } Condition; #define THREAD_ENTRY int typedef THREAD_ENTRY (*ThreadEntry)(void*); +#define THREAD_EXIT(RES) return RES static inline int MutexInit(Mutex* mutex) { Mutex id = sceKernelCreateMutex("mutex", 0, 0, 0); diff --git a/include/mgba-util/platform/switch/threading.h b/include/mgba-util/platform/switch/threading.h index 76f1ae8b5..52419fa28 100644 --- a/include/mgba-util/platform/switch/threading.h +++ b/include/mgba-util/platform/switch/threading.h @@ -11,6 +11,7 @@ #include #define THREAD_ENTRY void +#define THREAD_EXIT(RES) return typedef ThreadFunc ThreadEntry; typedef CondVar Condition; diff --git a/include/mgba-util/platform/windows/getopt.h b/include/mgba-util/platform/windows/getopt.h index 5ea2dbe6f..22a196ef6 100644 --- a/include/mgba-util/platform/windows/getopt.h +++ b/include/mgba-util/platform/windows/getopt.h @@ -27,6 +27,8 @@ extern "C" { #endif +struct option; + #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ #ifdef REPLACE_GETOPT diff --git a/include/mgba-util/platform/windows/threading.h b/include/mgba-util/platform/windows/threading.h index 9be6fe53a..3f5de5a77 100644 --- a/include/mgba-util/platform/windows/threading.h +++ b/include/mgba-util/platform/windows/threading.h @@ -12,6 +12,7 @@ #include #define THREAD_ENTRY DWORD WINAPI typedef THREAD_ENTRY ThreadEntry(LPVOID); +#define THREAD_EXIT(RES) return RES typedef HANDLE Thread; typedef CRITICAL_SECTION Mutex; diff --git a/include/mgba-util/socket.h b/include/mgba-util/socket.h index 9f07491bd..ff9d89626 100644 --- a/include/mgba-util/socket.h +++ b/include/mgba-util/socket.h @@ -204,6 +204,7 @@ static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); #endif if (err) { + SocketCloseQuiet(sock); return INVALID_SOCKET; } @@ -433,9 +434,9 @@ static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Soc #else int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv); #endif - int r = 0; - int w = 0; - int e = 0; + size_t r = 0; + size_t w = 0; + size_t e = 0; Socket j; for (j = 0; j < maxFd; ++j) { if (reads && FD_ISSET(j, &rset)) { @@ -451,6 +452,21 @@ static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Soc ++e; } } + if (reads) { + for (; r < nSockets; ++r) { + reads[r] = INVALID_SOCKET; + } + } + if (writes) { + for (; w < nSockets; ++w) { + writes[w] = INVALID_SOCKET; + } + } + if (errors) { + for (; e < nSockets; ++e) { + errors[e] = INVALID_SOCKET; + } + } return result; } diff --git a/include/mgba-util/vector.h b/include/mgba-util/vector.h index a4ec71b65..8c0f11e45 100644 --- a/include/mgba-util/vector.h +++ b/include/mgba-util/vector.h @@ -34,6 +34,16 @@ CXX_GUARD_START size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \ void NAME ## Copy(struct NAME* dest, const struct NAME* src); +#ifdef NDEBUG +#define VECTOR_BOUNDS_CHECK(NAME, V, L) +#else +#define VECTOR_BOUNDS_CHECK(NAME, V, L) \ + if ((L) >= (V)->size) { \ + fprintf(stderr, "Vector type %s invalid access of index %" PRIuPTR " into vector of size %" PRIuPTR "\n", #NAME, (L), (V)->size); \ + abort(); \ + } +#endif + #define DEFINE_VECTOR(NAME, TYPE) \ void NAME ## Init(struct NAME* vector, size_t capacity) { \ vector->size = 0; \ @@ -50,9 +60,11 @@ CXX_GUARD_START vector->size = 0; \ } \ TYPE* NAME ## GetPointer(struct NAME* vector, size_t location) { \ + VECTOR_BOUNDS_CHECK(NAME, vector, location); \ return &vector->vector[location]; \ } \ TYPE const* NAME ## GetConstPointer(const struct NAME* vector, size_t location) { \ + VECTOR_BOUNDS_CHECK(NAME, vector, location); \ return &vector->vector[location]; \ } \ TYPE* NAME ## Append(struct NAME* vector) { \ @@ -78,10 +90,12 @@ CXX_GUARD_START vector->vector = realloc(vector->vector, vector->capacity * sizeof(TYPE)); \ } \ void NAME ## Shift(struct NAME* vector, size_t location, size_t difference) { \ + VECTOR_BOUNDS_CHECK(NAME, vector, location); \ memmove(&vector->vector[location], &vector->vector[location + difference], (vector->size - location - difference) * sizeof(TYPE)); \ vector->size -= difference; \ } \ void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference) { \ + VECTOR_BOUNDS_CHECK(NAME, vector, location); \ NAME ## Resize(vector, difference); \ memmove(&vector->vector[location + difference], &vector->vector[location], (vector->size - location - difference) * sizeof(TYPE)); \ } \ @@ -97,8 +111,16 @@ CXX_GUARD_START dest->size = src->size; \ } \ -DECLARE_VECTOR(StringList, char*); DECLARE_VECTOR(IntList, int); +DECLARE_VECTOR(SInt8List, int8_t); +DECLARE_VECTOR(SInt16List, int16_t); +DECLARE_VECTOR(SInt32List, int32_t); +DECLARE_VECTOR(SIntPtrList, intptr_t); +DECLARE_VECTOR(UInt8List, uint8_t); +DECLARE_VECTOR(UInt16List, uint16_t); +DECLARE_VECTOR(UInt32List, uint32_t); +DECLARE_VECTOR(UIntPtrList, uintptr_t); +DECLARE_VECTOR(StringList, char*); CXX_GUARD_END diff --git a/include/mgba-util/vfs.h b/include/mgba-util/vfs.h index 334f84419..eee68b99e 100644 --- a/include/mgba-util/vfs.h +++ b/include/mgba-util/vfs.h @@ -100,6 +100,9 @@ struct VFile* VFileFromFILE(FILE* file); void separatePath(const char* path, char* dirname, char* basename, char* extension); +bool isAbsolute(const char* path); +void makeAbsolute(const char* path, const char* base, char* out); + struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)); struct VFile* VDirFindNextAvailable(struct VDir*, const char* basename, const char* infix, const char* suffix, int mode); diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 80184876b..2082c11db 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -33,6 +33,7 @@ struct mCoreOptions { int frameskip; bool rewindEnable; int rewindBufferCapacity; + int rewindBufferInterval; float fpsTarget; size_t audioBuffers; unsigned sampleRate; @@ -71,8 +72,9 @@ bool mCoreConfigSavePath(const struct mCoreConfig*, const char* path); bool mCoreConfigLoadVFile(struct mCoreConfig*, struct VFile* vf); bool mCoreConfigSaveVFile(const struct mCoreConfig*, struct VFile* vf); -void mCoreConfigMakePortable(const struct mCoreConfig*); +void mCoreConfigMakePortable(const struct mCoreConfig*, const char* path); void mCoreConfigDirectory(char* out, size_t outLength); +void mCoreConfigPortableIniPath(char* out, size_t outLength); void mCoreConfigPortablePath(char* out, size_t outLength); bool mCoreConfigIsPortable(void); #endif diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index d3f2b4e04..052e36795 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -65,8 +65,13 @@ struct mCore { void (*setSync)(struct mCore*, struct mCoreSync*); void (*loadConfig)(struct mCore*, const struct mCoreConfig*); void (*reloadConfigOption)(struct mCore*, const char* option, const struct mCoreConfig*); + void (*setOverride)(struct mCore*, const void* override); + + void (*baseVideoSize)(const struct mCore*, unsigned* width, unsigned* height); + void (*currentVideoSize)(const struct mCore*, unsigned* width, unsigned* height); + unsigned (*videoScale)(const struct mCore*); + size_t (*screenRegions)(const struct mCore*, const struct mCoreScreenRegion**); - void (*desiredVideoDimensions)(const struct mCore*, unsigned* width, unsigned* height); void (*setVideoBuffer)(struct mCore*, color_t* buffer, size_t stride); void (*setVideoGLTex)(struct mCore*, unsigned texid); @@ -116,6 +121,7 @@ struct mCore { void (*getGameCode)(const struct mCore*, char* title); void (*setPeripheral)(struct mCore*, int type, void*); + void* (*getPeripheral)(struct mCore*, int type); uint32_t (*busRead8)(struct mCore*, uint32_t address); uint32_t (*busRead16)(struct mCore*, uint32_t address); diff --git a/include/mgba/core/input.h b/include/mgba/core/input.h index f7ef212a5..f5d8002ed 100644 --- a/include/mgba/core/input.h +++ b/include/mgba/core/input.h @@ -55,6 +55,7 @@ int mInputMapKeyBits(const struct mInputMap* map, uint32_t type, uint32_t bits, void mInputBindKey(struct mInputMap*, uint32_t type, int key, int input); int mInputQueryBinding(const struct mInputMap*, uint32_t type, int input); void mInputUnbindKey(struct mInputMap*, uint32_t type, int input); +void mInputUnbindAllKeys(struct mInputMap*, uint32_t type); int mInputMapAxis(const struct mInputMap*, uint32_t type, int axis, int value); int mInputClearAxis(const struct mInputMap*, uint32_t type, int axis, int keys); @@ -69,6 +70,7 @@ void mInputBindHat(struct mInputMap*, uint32_t type, int id, const struct mInput bool mInputQueryHat(const struct mInputMap*, uint32_t type, int id, struct mInputHatBindings* bindings); void mInputUnbindHat(struct mInputMap*, uint32_t type, int id); void mInputUnbindAllHats(struct mInputMap*, uint32_t type); +void mInputEnumerateHats(const struct mInputMap*, uint32_t type, void (handler(int hat, const struct mInputHatBindings* bindings, void* user)), void* user); bool mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*); void mInputMapSave(const struct mInputMap*, uint32_t type, struct Configuration*); diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index 9046d1a4f..f1af5e50d 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -10,165 +10,14 @@ CXX_GUARD_START +#include #include struct mCore; struct mStateExtdataItem; -#ifdef COLOR_16_BIT -typedef uint16_t color_t; -#define BYTES_PER_PIXEL 2 -#else -typedef uint32_t color_t; -#define BYTES_PER_PIXEL 4 -#endif - -#define M_R5(X) ((X) & 0x1F) -#define M_G5(X) (((X) >> 5) & 0x1F) -#define M_B5(X) (((X) >> 10) & 0x1F) - -#define M_R8(X) (((((X) << 3) & 0xF8) * 0x21) >> 5) -#define M_G8(X) (((((X) >> 2) & 0xF8) * 0x21) >> 5) -#define M_B8(X) (((((X) >> 7) & 0xF8) * 0x21) >> 5) - -#define M_RGB5_TO_BGR8(X) ((M_R5(X) << 3) | (M_G5(X) << 11) | (M_B5(X) << 19)) -#define M_RGB5_TO_RGB8(X) ((M_R5(X) << 19) | (M_G5(X) << 11) | (M_B5(X) << 3)) -#define M_RGB8_TO_BGR5(X) ((((X) & 0xF8) >> 3) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 9)) -#define M_RGB8_TO_RGB5(X) ((((X) & 0xF8) << 7) | (((X) & 0xF800) >> 6) | (((X) & 0xF80000) >> 19)) - -#ifndef COLOR_16_BIT -#define M_COLOR_RED 0x000000FF -#define M_COLOR_GREEN 0x0000FF00 -#define M_COLOR_BLUE 0x00FF0000 -#define M_COLOR_ALPHA 0xFF000000 -#define M_COLOR_WHITE 0x00FFFFFF - -#define M_RGB8_TO_NATIVE(X) (((X) & 0x00FF00) | (((X) & 0x0000FF) << 16) | (((X) & 0xFF0000) >> 16)) -#elif defined(COLOR_5_6_5) -#define M_COLOR_RED 0x001F -#define M_COLOR_GREEN 0x07E0 -#define M_COLOR_BLUE 0xF800 -#define M_COLOR_ALPHA 0x0000 -#define M_COLOR_WHITE 0xFFDF - -#define M_RGB8_TO_NATIVE(X) ((((X) & 0xF8) << 8) | (((X) & 0xFC00) >> 5) | (((X) & 0xF80000) >> 19)) -#else -#define M_COLOR_RED 0x001F -#define M_COLOR_GREEN 0x03E0 -#define M_COLOR_BLUE 0x7C00 -#define M_COLOR_ALPHA 0x1000 -#define M_COLOR_WHITE 0x7FFF - -#define M_RGB8_TO_NATIVE(X) M_RGB8_TO_BGR5(X) -#endif - -#ifndef PYCPARSE -static inline color_t mColorFrom555(uint16_t value) { -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - color_t color = 0; - color |= (value & 0x001F) << 11; - color |= (value & 0x03E0) << 1; - color |= (value & 0x7C00) >> 10; -#else - color_t color = value; -#endif -#else - color_t color = M_RGB5_TO_BGR8(value); - color |= (color >> 5) & 0x070707; -#endif - return color; -} - -ATTRIBUTE_UNUSED static unsigned mColorMix5Bit(int weightA, unsigned colorA, int weightB, unsigned colorB) { - unsigned c = 0; - unsigned a, b; -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - a = colorA & 0xF81F; - b = colorB & 0xF81F; - a |= (colorA & 0x7C0) << 16; - b |= (colorB & 0x7C0) << 16; - c = ((a * weightA + b * weightB) / 16); - if (c & 0x08000000) { - c = (c & ~0x0FC00000) | 0x07C00000; - } - if (c & 0x0020) { - c = (c & ~0x003F) | 0x001F; - } - if (c & 0x10000) { - c = (c & ~0x1F800) | 0xF800; - } - c = (c & 0xF81F) | ((c >> 16) & 0x07C0); -#else - a = colorA & 0x7C1F; - b = colorB & 0x7C1F; - a |= (colorA & 0x3E0) << 16; - b |= (colorB & 0x3E0) << 16; - c = ((a * weightA + b * weightB) / 16); - if (c & 0x04000000) { - c = (c & ~0x07E00000) | 0x03E00000; - } - if (c & 0x0020) { - c = (c & ~0x003F) | 0x001F; - } - if (c & 0x8000) { - c = (c & ~0xF800) | 0x7C00; - } - c = (c & 0x7C1F) | ((c >> 16) & 0x03E0); -#endif -#else - a = colorA & 0xFF; - b = colorB & 0xFF; - c |= ((a * weightA + b * weightB) / 16) & 0x1FF; - if (c & 0x00000100) { - c = 0x000000FF; - } - - a = colorA & 0xFF00; - b = colorB & 0xFF00; - c |= ((a * weightA + b * weightB) / 16) & 0x1FF00; - if (c & 0x00010000) { - c = (c & 0x000000FF) | 0x0000FF00; - } - - a = colorA & 0xFF0000; - b = colorB & 0xFF0000; - c |= ((a * weightA + b * weightB) / 16) & 0x1FF0000; - if (c & 0x01000000) { - c = (c & 0x0000FFFF) | 0x00FF0000; - } -#endif - return c; -} -#endif - struct blip_t; -enum mColorFormat { - mCOLOR_XBGR8 = 0x00001, - mCOLOR_XRGB8 = 0x00002, - mCOLOR_BGRX8 = 0x00004, - mCOLOR_RGBX8 = 0x00008, - mCOLOR_ABGR8 = 0x00010, - mCOLOR_ARGB8 = 0x00020, - mCOLOR_BGRA8 = 0x00040, - mCOLOR_RGBA8 = 0x00080, - mCOLOR_RGB5 = 0x00100, - mCOLOR_BGR5 = 0x00200, - mCOLOR_RGB565 = 0x00400, - mCOLOR_BGR565 = 0x00800, - mCOLOR_ARGB5 = 0x01000, - mCOLOR_ABGR5 = 0x02000, - mCOLOR_RGBA5 = 0x04000, - mCOLOR_BGRA5 = 0x08000, - mCOLOR_RGB8 = 0x10000, - mCOLOR_BGR8 = 0x20000, - mCOLOR_L8 = 0x40000, - - mCOLOR_ANY = -1 -}; - enum mCoreFeature { mCORE_FEATURE_OPENGL = 1, }; @@ -293,6 +142,15 @@ struct mCoreMemoryBlock { uint32_t segmentStart; }; +struct mCoreScreenRegion { + size_t id; + const char* description; + int16_t x; + int16_t y; + int16_t w; + int16_t h; +}; + enum mCoreRegisterType { mCORE_REGISTER_GPR = 0, mCORE_REGISTER_FPR, diff --git a/include/mgba/core/log.h b/include/mgba/core/log.h index 9f55ec772..892a8f2f9 100644 --- a/include/mgba/core/log.h +++ b/include/mgba/core/log.h @@ -44,6 +44,9 @@ struct mStandardLogger { struct mLogger* mLogGetContext(void); void mLogSetDefaultLogger(struct mLogger*); +void mLogSetThreadLogger(struct mLogger*); +struct mLogger* mLogGetThreadLogger(void); + int mLogGenerateCategory(const char*, const char*); const char* mLogCategoryName(int); const char* mLogCategoryId(int); diff --git a/include/mgba/core/rewind.h b/include/mgba/core/rewind.h index 04549761d..9d2595557 100644 --- a/include/mgba/core/rewind.h +++ b/include/mgba/core/rewind.h @@ -24,6 +24,7 @@ struct mCoreRewindContext { size_t size; struct VFile* previousState; struct VFile* currentState; + int rewindFrameCounter; #ifndef DISABLE_THREADING bool onThread; diff --git a/include/mgba/core/serialize.h b/include/mgba/core/serialize.h index 59ca1c19f..ee9de69a1 100644 --- a/include/mgba/core/serialize.h +++ b/include/mgba/core/serialize.h @@ -16,6 +16,7 @@ enum mStateExtdataTag { EXTDATA_SAVEDATA = 2, EXTDATA_CHEATS = 3, EXTDATA_RTC = 4, + EXTDATA_SCREENSHOT_DIMENSIONS = 5, EXTDATA_META_TIME = 0x101, EXTDATA_META_CREATOR = 0x102, EXTDATA_MAX diff --git a/include/mgba/core/thread.h b/include/mgba/core/thread.h index fee447ae7..d3d8a9e92 100644 --- a/include/mgba/core/thread.h +++ b/include/mgba/core/thread.h @@ -128,7 +128,6 @@ void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool); void mCoreThreadRewindParamsChanged(struct mCoreThread* threadContext); struct mCoreThread* mCoreThreadGet(void); -struct mLogger* mCoreThreadLogger(void); CXX_GUARD_END diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index b460623e3..eb69faaf4 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -10,24 +10,60 @@ CXX_GUARD_START +#define INSN_LENGTH_MAX 4 + #include #include +#include #include -#include mLOG_DECLARE_CATEGORY(DEBUGGER); extern const uint32_t DEBUGGER_ID; +DECL_BITFIELD(mDebuggerAccessLogFlags, uint8_t); +DECL_BIT(mDebuggerAccessLogFlags, Read, 0); +DECL_BIT(mDebuggerAccessLogFlags, Write, 1); +DECL_BIT(mDebuggerAccessLogFlags, Execute, 2); +DECL_BIT(mDebuggerAccessLogFlags, Abort, 3); +DECL_BIT(mDebuggerAccessLogFlags, Access8, 4); +DECL_BIT(mDebuggerAccessLogFlags, Access16, 5); +DECL_BIT(mDebuggerAccessLogFlags, Access32, 6); +DECL_BIT(mDebuggerAccessLogFlags, Access64, 7); + +DECL_BITFIELD(mDebuggerAccessLogFlagsEx, uint16_t); +DECL_BIT(mDebuggerAccessLogFlagsEx, AccessProgram, 0); +DECL_BIT(mDebuggerAccessLogFlagsEx, AccessDMA, 1); +DECL_BIT(mDebuggerAccessLogFlagsEx, AccessSystem, 2); +DECL_BIT(mDebuggerAccessLogFlagsEx, AccessDecompress, 3); +DECL_BIT(mDebuggerAccessLogFlagsEx, AccessCopy, 4); + +DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorIllegalOpcode, 8); +DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorAccessRead, 9); +DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorAccessWrite, 10); +DECL_BIT(mDebuggerAccessLogFlagsEx, ErrorAccessExecute, 11); +DECL_BIT(mDebuggerAccessLogFlagsEx, Private0, 12); +DECL_BIT(mDebuggerAccessLogFlagsEx, Private1, 13); +DECL_BIT(mDebuggerAccessLogFlagsEx, Private2, 14); +DECL_BIT(mDebuggerAccessLogFlagsEx, Private3, 15); + +DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteARM, 14); +DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteThumb, 15); + +DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteOpcode, 14); +DECL_BIT(mDebuggerAccessLogFlagsEx, ExecuteOperand, 15); + enum mDebuggerType { DEBUGGER_NONE = 0, DEBUGGER_CUSTOM, DEBUGGER_CLI, DEBUGGER_GDB, + DEBUGGER_ACCESS_LOGGER, DEBUGGER_MAX }; enum mDebuggerState { + DEBUGGER_CREATED = 0, DEBUGGER_PAUSED, DEBUGGER_RUNNING, DEBUGGER_CALLBACK, @@ -56,8 +92,19 @@ enum mDebuggerEntryReason { DEBUGGER_ENTER_STACK }; +enum mStackTraceMode { + STACK_TRACE_DISABLED = 0, + STACK_TRACE_ENABLED = 1, + STACK_TRACE_BREAK_ON_RETURN = 2, + STACK_TRACE_BREAK_ON_CALL = 4, + STACK_TRACE_BREAK_ON_BOTH = STACK_TRACE_BREAK_ON_RETURN | STACK_TRACE_BREAK_ON_CALL +}; + +struct mDebuggerModule; struct mDebuggerEntryInfo { uint32_t address; + int segment; + int width; union { struct { uint32_t oldValue; @@ -76,6 +123,7 @@ struct mDebuggerEntryInfo { } st; } type; ssize_t pointId; + struct mDebuggerModule* target; }; struct mBreakpoint { @@ -95,8 +143,39 @@ struct mWatchpoint { struct ParseTree* condition; }; +struct mDebuggerInstructionInfo { + uint32_t address; + int segment; + unsigned width; + mDebuggerAccessLogFlags flags[INSN_LENGTH_MAX]; + mDebuggerAccessLogFlagsEx flagsEx[INSN_LENGTH_MAX]; +}; + DECLARE_VECTOR(mBreakpointList, struct mBreakpoint); DECLARE_VECTOR(mWatchpointList, struct mWatchpoint); +DECLARE_VECTOR(mDebuggerModuleList, struct mDebuggerModule*); + +struct mStackFrame { + int callSegment; + uint32_t callAddress; + int entrySegment; + uint32_t entryAddress; + int frameBaseSegment; + uint32_t frameBaseAddress; + void* regs; + bool finished; + bool breakWhenFinished; + bool interrupt; +}; + +DECLARE_VECTOR(mStackFrames, struct mStackFrame); + +struct mStackTrace { + struct mStackFrames stack; + size_t registersSize; + + void (*formatRegisters)(struct mStackFrame* frame, char* out, size_t* length); +}; struct mDebugger; struct ParseTree; @@ -111,47 +190,73 @@ struct mDebuggerPlatform { void (*checkBreakpoints)(struct mDebuggerPlatform*); bool (*clearBreakpoint)(struct mDebuggerPlatform*, ssize_t id); - ssize_t (*setBreakpoint)(struct mDebuggerPlatform*, const struct mBreakpoint*); - void (*listBreakpoints)(struct mDebuggerPlatform*, struct mBreakpointList*); + ssize_t (*setBreakpoint)(struct mDebuggerPlatform*, struct mDebuggerModule*, const struct mBreakpoint*); + void (*listBreakpoints)(struct mDebuggerPlatform*, struct mDebuggerModule*, struct mBreakpointList*); - ssize_t (*setWatchpoint)(struct mDebuggerPlatform*, const struct mWatchpoint*); - void (*listWatchpoints)(struct mDebuggerPlatform*, struct mWatchpointList*); + ssize_t (*setWatchpoint)(struct mDebuggerPlatform*, struct mDebuggerModule*, const struct mWatchpoint*); + void (*listWatchpoints)(struct mDebuggerPlatform*, struct mDebuggerModule*, struct mWatchpointList*); void (*trace)(struct mDebuggerPlatform*, char* out, size_t* length); bool (*lookupIdentifier)(struct mDebuggerPlatform*, const char* name, int32_t* value, int* segment); - uint32_t (*getStackTraceMode)(struct mDebuggerPlatform*); - void (*setStackTraceMode)(struct mDebuggerPlatform*, uint32_t mode); + enum mStackTraceMode (*getStackTraceMode)(struct mDebuggerPlatform*); + void (*setStackTraceMode)(struct mDebuggerPlatform*, enum mStackTraceMode mode); bool (*updateStackTrace)(struct mDebuggerPlatform* d); + + void (*nextInstructionInfo)(struct mDebuggerPlatform* d, struct mDebuggerInstructionInfo* info); }; struct mDebugger { struct mCPUComponent d; struct mDebuggerPlatform* platform; enum mDebuggerState state; - enum mDebuggerType type; struct mCore* core; struct mScriptBridge* bridge; struct mStackTrace stackTrace; - void (*init)(struct mDebugger*); - void (*deinit)(struct mDebugger*); - - void (*paused)(struct mDebugger*); - void (*update)(struct mDebugger*); - void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); - void (*custom)(struct mDebugger*); - - void (*interrupt)(struct mDebugger*); + struct mDebuggerModuleList modules; + struct Table pointOwner; }; -struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore*); +struct mDebuggerModule { + struct mDebugger* p; + enum mDebuggerType type; + bool isPaused; + bool needsCallback; + + void (*init)(struct mDebuggerModule*); + void (*deinit)(struct mDebuggerModule*); + + void (*paused)(struct mDebuggerModule*, int32_t timeoutMs); + void (*update)(struct mDebuggerModule*); + void (*entered)(struct mDebuggerModule*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); + void (*custom)(struct mDebuggerModule*); + + void (*interrupt)(struct mDebuggerModule*); +}; + +void mDebuggerInit(struct mDebugger*); +void mDebuggerDeinit(struct mDebugger*); + void mDebuggerAttach(struct mDebugger*, struct mCore*); +void mDebuggerAttachModule(struct mDebugger*, struct mDebuggerModule*); +void mDebuggerDetachModule(struct mDebugger*, struct mDebuggerModule*); +void mDebuggerRunTimeout(struct mDebugger* debugger, int32_t timeoutMs); void mDebuggerRun(struct mDebugger*); void mDebuggerRunFrame(struct mDebugger*); void mDebuggerEnter(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +void mDebuggerInterrupt(struct mDebugger*); +void mDebuggerUpdatePaused(struct mDebugger*); +void mDebuggerShutdown(struct mDebugger*); +void mDebuggerUpdate(struct mDebugger*); + +bool mDebuggerIsShutdown(const struct mDebugger*); + +struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mCore*); +void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule*); + bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment); CXX_GUARD_END diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index 0f9c543d1..17af655fe 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -25,8 +25,9 @@ struct mArguments { struct Table configOverrides; - enum mDebuggerType debuggerType; bool debugAtStart; + bool debugCli; + bool debugGdb; bool showHelp; bool showVersion; }; @@ -58,6 +59,8 @@ void version(const char* arg0); bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struct mSubParser* subparsers, int nSubparsers); void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparsers, int nSubparsers, struct mCoreConfig* config); +bool mArgumentsApplyDebugger(const struct mArguments*, struct mCore*, struct mDebugger*); +void mArgumentsApplyFileLoads(const struct mArguments*, struct mCore*); void mArgumentsDeinit(struct mArguments* args); void mSubParserGraphicsInit(struct mSubParser* parser, struct mGraphicsOpts* opts); diff --git a/include/mgba/feature/proxy-backend.h b/include/mgba/feature/proxy-backend.h new file mode 100644 index 000000000..8c0b9e427 --- /dev/null +++ b/include/mgba/feature/proxy-backend.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef PROXY_BACKEND_H +#define PROXY_BACKEND_H + +#include + +CXX_GUARD_START + +#include +#include +#include + +enum mVideoBackendCommandType { + mVB_CMD_DUMMY = 0, + mVB_CMD_INIT, + mVB_CMD_DEINIT, + mVB_CMD_SET_LAYER_DIMENSIONS, + mVB_CMD_LAYER_DIMENSIONS, + mVB_CMD_SWAP, + mVB_CMD_CLEAR, + mVB_CMD_CONTEXT_RESIZED, + mVB_CMD_SET_IMAGE_SIZE, + mVB_CMD_IMAGE_SIZE, + mVB_CMD_SET_IMAGE, + mVB_CMD_DRAW_FRAME, +}; + +union mVideoBackendCommandData { + struct mRectangle dims; + struct { + int width; + int height; + } s; + struct { + unsigned width; + unsigned height; + } u; + const void* image; +}; + +struct mVideoBackendCommand { + enum mVideoBackendCommandType cmd; + + union { + WHandle handle; + enum VideoLayer layer; + }; + union mVideoBackendCommandData data; +}; + +struct mVideoProxyBackend { + struct VideoBackend d; + struct VideoBackend* backend; + + struct RingFIFO in; + struct RingFIFO out; + + Mutex inLock; + Mutex outLock; + Condition inWait; + Condition outWait; + + void (*wakeupCb)(struct mVideoProxyBackend*, void* context); + void* context; +}; + +void mVideoProxyBackendInit(struct mVideoProxyBackend* proxy, struct VideoBackend* backend); +void mVideoProxyBackendDeinit(struct mVideoProxyBackend* proxy); + +void mVideoProxyBackendSubmit(struct mVideoProxyBackend* proxy, const struct mVideoBackendCommand* cmd, union mVideoBackendCommandData* out); +bool mVideoProxyBackendRun(struct mVideoProxyBackend* proxy, bool block); + +bool mVideoProxyBackendCommandIsBlocking(enum mVideoBackendCommandType); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/feature/video-backend.h b/include/mgba/feature/video-backend.h new file mode 100644 index 000000000..adf6f8395 --- /dev/null +++ b/include/mgba/feature/video-backend.h @@ -0,0 +1,81 @@ +/* Copyright (c) 2013-2015 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/. */ +#ifndef VIDEO_BACKEND_H +#define VIDEO_BACKEND_H + +#include + +CXX_GUARD_START + +#include +#include + +#ifdef _WIN32 +#include +typedef HWND WHandle; +#else +typedef void* WHandle; +#endif + +mLOG_DECLARE_CATEGORY(VIDEO); + +enum VideoLayer { + VIDEO_LAYER_BACKGROUND = 0, + VIDEO_LAYER_BEZEL, + VIDEO_LAYER_IMAGE, + VIDEO_LAYER_OVERLAY0, + VIDEO_LAYER_OVERLAY1, + VIDEO_LAYER_OVERLAY2, + VIDEO_LAYER_OVERLAY3, + VIDEO_LAYER_OVERLAY4, + VIDEO_LAYER_OVERLAY5, + VIDEO_LAYER_OVERLAY6, + VIDEO_LAYER_OVERLAY7, + VIDEO_LAYER_OVERLAY8, + VIDEO_LAYER_OVERLAY9, + VIDEO_LAYER_MAX +}; + +#define VIDEO_LAYER_OVERLAY_COUNT VIDEO_LAYER_MAX - VIDEO_LAYER_OVERLAY0 + +struct VideoBackend { + void (*init)(struct VideoBackend*, WHandle handle); + void (*deinit)(struct VideoBackend*); + void (*setLayerDimensions)(struct VideoBackend*, enum VideoLayer, const struct mRectangle*); + void (*layerDimensions)(const struct VideoBackend*, enum VideoLayer, struct mRectangle*); + void (*swap)(struct VideoBackend*); + void (*clear)(struct VideoBackend*); + void (*contextResized)(struct VideoBackend*, unsigned w, unsigned h); + void (*setImageSize)(struct VideoBackend*, enum VideoLayer, int w, int h); + void (*imageSize)(struct VideoBackend*, enum VideoLayer, int* w, int* h); + void (*setImage)(struct VideoBackend*, enum VideoLayer, const void* frame); + void (*drawFrame)(struct VideoBackend*); + + void* user; + + bool filter; + bool lockAspectRatio; + bool lockIntegerScaling; + bool interframeBlending; + enum VideoLayer cropToLayer; +}; + +struct VideoShader { + const char* name; + const char* author; + const char* description; + void* preprocessShader; + void* passes; + size_t nPasses; +}; + +void VideoBackendGetFrame(const struct VideoBackend*, struct mRectangle* frame); +void VideoBackendGetFrameSize(const struct VideoBackend*, unsigned* width, unsigned* height); +void VideoBackendRecenter(struct VideoBackend* v, unsigned scale); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/gb/interface.h b/include/mgba/gb/interface.h index 0ec54559f..ecd99e2f9 100644 --- a/include/mgba/gb/interface.h +++ b/include/mgba/gb/interface.h @@ -71,6 +71,7 @@ struct VFile; bool GBIsROM(struct VFile* vf); bool GBIsBIOS(struct VFile* vf); +bool GBIsCompatibleBIOS(struct VFile* vf, enum GBModel model); enum GBModel GBNameToModel(const char*); const char* GBModelToName(enum GBModel); diff --git a/include/mgba/internal/arm/debugger/debugger.h b/include/mgba/internal/arm/debugger/debugger.h index cbce4f120..a18a13427 100644 --- a/include/mgba/internal/arm/debugger/debugger.h +++ b/include/mgba/internal/arm/debugger/debugger.h @@ -36,7 +36,7 @@ struct ARMDebugger { struct ARMMemory originalMemory; ssize_t nextId; - uint32_t stackTraceMode; + enum mStackTraceMode stackTraceMode; void (*entered)(struct mDebugger*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); @@ -45,7 +45,7 @@ struct ARMDebugger { }; struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void); -ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, uint32_t address, enum ExecutionMode mode); +ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* debugger, struct mDebuggerModule* owner, uint32_t address, enum ExecutionMode mode); CXX_GUARD_END diff --git a/include/mgba/internal/debugger/access-logger.h b/include/mgba/internal/debugger/access-logger.h new file mode 100644 index 000000000..26186ac20 --- /dev/null +++ b/include/mgba/internal/debugger/access-logger.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef ACCESS_LOGGER_H +#define ACCESS_LOGGER_H + +#include + +CXX_GUARD_START + +#include +#include + +DECL_BITFIELD(mDebuggerAccessLogRegionFlags, uint64_t); +DECL_BIT(mDebuggerAccessLogRegionFlags, HasExBlock, 0); + +struct mDebuggerAccessLogRegion { + uint32_t start; + uint32_t end; + uint32_t size; + uint32_t segmentStart; + mDebuggerAccessLogFlags* block; + mDebuggerAccessLogFlagsEx* blockEx; +}; + +DECLARE_VECTOR(mDebuggerAccessLogRegionList, struct mDebuggerAccessLogRegion); + +struct mDebuggerAccessLog; +struct mDebuggerAccessLogger { + struct mDebuggerModule d; + struct VFile* backing; + struct mDebuggerAccessLog* mapped; + struct mDebuggerAccessLogRegionList regions; +}; + +void mDebuggerAccessLoggerInit(struct mDebuggerAccessLogger*); +void mDebuggerAccessLoggerDeinit(struct mDebuggerAccessLogger*); + +bool mDebuggerAccessLoggerOpen(struct mDebuggerAccessLogger*, struct VFile*, int mode); +bool mDebuggerAccessLoggerClose(struct mDebuggerAccessLogger*); + +int mDebuggerAccessLoggerWatchMemoryBlockId(struct mDebuggerAccessLogger*, size_t id, mDebuggerAccessLogRegionFlags); +int mDebuggerAccessLoggerWatchMemoryBlockName(struct mDebuggerAccessLogger*, const char* internalName, mDebuggerAccessLogRegionFlags); + +bool mDebuggerAccessLoggerCreateShadowFile(struct mDebuggerAccessLogger*, int region, struct VFile*, uint8_t fill); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/internal/debugger/cli-debugger.h b/include/mgba/internal/debugger/cli-debugger.h index 1fc5df369..87ba9db88 100644 --- a/include/mgba/internal/debugger/cli-debugger.h +++ b/include/mgba/internal/debugger/cli-debugger.h @@ -73,6 +73,7 @@ struct CLIDebuggerBackend { ATTRIBUTE_FORMAT(printf, 2, 3) void (*printf)(struct CLIDebuggerBackend*, const char* fmt, ...); + int (*poll)(struct CLIDebuggerBackend*, int32_t timeoutMs); const char* (*readline)(struct CLIDebuggerBackend*, size_t* len); void (*lineAppend)(struct CLIDebuggerBackend*, const char* line); const char* (*historyLast)(struct CLIDebuggerBackend*, size_t* len); @@ -81,7 +82,7 @@ struct CLIDebuggerBackend { }; struct CLIDebugger { - struct mDebugger d; + struct mDebuggerModule d; struct CLIDebuggerSystem* system; struct CLIDebuggerBackend* backend; diff --git a/src/feature/editline/cli-el-backend.h b/include/mgba/internal/debugger/cli-el-backend.h similarity index 82% rename from src/feature/editline/cli-el-backend.h rename to include/mgba/internal/debugger/cli-el-backend.h index 89ceec641..312798a38 100644 --- a/src/feature/editline/cli-el-backend.h +++ b/include/mgba/internal/debugger/cli-el-backend.h @@ -14,13 +14,6 @@ CXX_GUARD_START #include -struct CLIDebuggerEditLineBackend { - struct CLIDebuggerBackend d; - - EditLine* elstate; - History* histate; -}; - struct CLIDebuggerBackend* CLIDebuggerEditLineBackendCreate(void); CXX_GUARD_END diff --git a/include/mgba/internal/debugger/gdb-stub.h b/include/mgba/internal/debugger/gdb-stub.h index b76b52452..6110ec499 100644 --- a/include/mgba/internal/debugger/gdb-stub.h +++ b/include/mgba/internal/debugger/gdb-stub.h @@ -14,7 +14,7 @@ CXX_GUARD_START #include -#define GDB_STUB_MAX_LINE 1200 +#define GDB_STUB_MAX_LINE 1400 #define GDB_STUB_INTERVAL 32 enum GDBStubAckState { @@ -31,7 +31,7 @@ enum GDBWatchpointsBehvaior { }; struct GDBStub { - struct mDebugger d; + struct mDebuggerModule d; char line[GDB_STUB_MAX_LINE]; char outgoing[GDB_STUB_MAX_LINE]; @@ -41,7 +41,6 @@ struct GDBStub { Socket socket; Socket connection; - bool shouldBlock; int untilPoll; bool supportsSwbreak; @@ -56,7 +55,7 @@ bool GDBStubListen(struct GDBStub*, int port, const struct Address* bindAddress, void GDBStubHangup(struct GDBStub*); void GDBStubShutdown(struct GDBStub*); -void GDBStubUpdate(struct GDBStub*); +bool GDBStubUpdate(struct GDBStub*, int timeoutMs); CXX_GUARD_END diff --git a/include/mgba/internal/debugger/stack-trace.h b/include/mgba/internal/debugger/stack-trace.h index 11268aae3..d99bd2436 100644 --- a/include/mgba/internal/debugger/stack-trace.h +++ b/include/mgba/internal/debugger/stack-trace.h @@ -12,43 +12,13 @@ CXX_GUARD_START #include #include +#include #include -struct mDebuggerSymbols; - -enum mStackTraceMode { - STACK_TRACE_DISABLED = 0, - STACK_TRACE_ENABLED = 1, - STACK_TRACE_BREAK_ON_RETURN = 2, - STACK_TRACE_BREAK_ON_CALL = 4, - STACK_TRACE_BREAK_ON_BOTH = STACK_TRACE_BREAK_ON_RETURN | STACK_TRACE_BREAK_ON_CALL -}; - -struct mStackFrame { - int callSegment; - uint32_t callAddress; - int entrySegment; - uint32_t entryAddress; - int frameBaseSegment; - uint32_t frameBaseAddress; - void* regs; - bool finished; - bool breakWhenFinished; - bool interrupt; -}; - -DECLARE_VECTOR(mStackFrames, struct mStackFrame); - -struct mStackTrace { - struct mStackFrames stack; - size_t registersSize; - - void (*formatRegisters)(struct mStackFrame* frame, char* out, size_t* length); -}; - void mStackTraceInit(struct mStackTrace* stack, size_t registersSize); void mStackTraceDeinit(struct mStackTrace* stack); +struct mDebuggerSymbols; void mStackTraceClear(struct mStackTrace* stack); size_t mStackTraceGetDepth(struct mStackTrace* stack); struct mStackFrame* mStackTracePush(struct mStackTrace* stack, uint32_t pc, uint32_t destAddress, uint32_t sp, void* regs); diff --git a/include/mgba/internal/gb/extra/cli.h b/include/mgba/internal/gb/debugger/cli.h similarity index 100% rename from include/mgba/internal/gb/extra/cli.h rename to include/mgba/internal/gb/debugger/cli.h diff --git a/include/mgba/internal/gb/memory.h b/include/mgba/internal/gb/memory.h index d3a42a229..052a9f77e 100644 --- a/include/mgba/internal/gb/memory.h +++ b/include/mgba/internal/gb/memory.h @@ -292,7 +292,7 @@ struct GBMemory { int currentSramBank1; uint8_t* sramBank1; - unsigned cartBusDecay; + int cartBusDecay; uint16_t cartBusPc; uint8_t cartBus; diff --git a/include/mgba/internal/gb/serialize.h b/include/mgba/internal/gb/serialize.h index f4433c495..e76d0accb 100644 --- a/include/mgba/internal/gb/serialize.h +++ b/include/mgba/internal/gb/serialize.h @@ -419,6 +419,9 @@ struct GBSerializedState { uint8_t locked; uint8_t bank0; } mmm01; + struct { + uint8_t registersActive; + } pocketCam; struct { uint64_t lastLatch; uint8_t reg; @@ -484,6 +487,7 @@ struct GBSerializedState { union { uint8_t huc3Registers[0x80]; + uint8_t pocketCamRegisters[0x36]; struct { uint8_t registers[4]; uint8_t reserved[4]; diff --git a/include/mgba/internal/gb/video.h b/include/mgba/internal/gb/video.h index 31c54b089..c9b179739 100644 --- a/include/mgba/internal/gb/video.h +++ b/include/mgba/internal/gb/video.h @@ -22,6 +22,9 @@ enum { GB_VIDEO_VBLANK_PIXELS = 10, GB_VIDEO_VERTICAL_TOTAL_PIXELS = 154, + SGB_VIDEO_HORIZONTAL_PIXELS = 256, + SGB_VIDEO_VERTICAL_PIXELS = 224, + // TODO: Figure out exact lengths GB_VIDEO_MODE_2_LENGTH = 80, GB_VIDEO_MODE_3_LENGTH_BASE = 172, diff --git a/include/mgba/internal/gba/extra/cli.h b/include/mgba/internal/gba/debugger/cli.h similarity index 100% rename from include/mgba/internal/gba/extra/cli.h rename to include/mgba/internal/gba/debugger/cli.h diff --git a/include/mgba/internal/gba/io.h b/include/mgba/internal/gba/io.h index fdd480037..197e19d62 100644 --- a/include/mgba/internal/gba/io.h +++ b/include/mgba/internal/gba/io.h @@ -12,158 +12,160 @@ CXX_GUARD_START #include +#define GBA_REG(X) (GBA_REG_ ## X >> 1) + enum GBAIORegisters { // Video - REG_DISPCNT = 0x000, - REG_GREENSWP = 0x002, - REG_DISPSTAT = 0x004, - REG_VCOUNT = 0x006, - REG_BG0CNT = 0x008, - REG_BG1CNT = 0x00A, - REG_BG2CNT = 0x00C, - REG_BG3CNT = 0x00E, - REG_BG0HOFS = 0x010, - REG_BG0VOFS = 0x012, - REG_BG1HOFS = 0x014, - REG_BG1VOFS = 0x016, - REG_BG2HOFS = 0x018, - REG_BG2VOFS = 0x01A, - REG_BG3HOFS = 0x01C, - REG_BG3VOFS = 0x01E, - REG_BG2PA = 0x020, - REG_BG2PB = 0x022, - REG_BG2PC = 0x024, - REG_BG2PD = 0x026, - REG_BG2X_LO = 0x028, - REG_BG2X_HI = 0x02A, - REG_BG2Y_LO = 0x02C, - REG_BG2Y_HI = 0x02E, - REG_BG3PA = 0x030, - REG_BG3PB = 0x032, - REG_BG3PC = 0x034, - REG_BG3PD = 0x036, - REG_BG3X_LO = 0x038, - REG_BG3X_HI = 0x03A, - REG_BG3Y_LO = 0x03C, - REG_BG3Y_HI = 0x03E, - REG_WIN0H = 0x040, - REG_WIN1H = 0x042, - REG_WIN0V = 0x044, - REG_WIN1V = 0x046, - REG_WININ = 0x048, - REG_WINOUT = 0x04A, - REG_MOSAIC = 0x04C, - REG_BLDCNT = 0x050, - REG_BLDALPHA = 0x052, - REG_BLDY = 0x054, + GBA_REG_DISPCNT = 0x000, + GBA_REG_GREENSWP = 0x002, + GBA_REG_DISPSTAT = 0x004, + GBA_REG_VCOUNT = 0x006, + GBA_REG_BG0CNT = 0x008, + GBA_REG_BG1CNT = 0x00A, + GBA_REG_BG2CNT = 0x00C, + GBA_REG_BG3CNT = 0x00E, + GBA_REG_BG0HOFS = 0x010, + GBA_REG_BG0VOFS = 0x012, + GBA_REG_BG1HOFS = 0x014, + GBA_REG_BG1VOFS = 0x016, + GBA_REG_BG2HOFS = 0x018, + GBA_REG_BG2VOFS = 0x01A, + GBA_REG_BG3HOFS = 0x01C, + GBA_REG_BG3VOFS = 0x01E, + GBA_REG_BG2PA = 0x020, + GBA_REG_BG2PB = 0x022, + GBA_REG_BG2PC = 0x024, + GBA_REG_BG2PD = 0x026, + GBA_REG_BG2X_LO = 0x028, + GBA_REG_BG2X_HI = 0x02A, + GBA_REG_BG2Y_LO = 0x02C, + GBA_REG_BG2Y_HI = 0x02E, + GBA_REG_BG3PA = 0x030, + GBA_REG_BG3PB = 0x032, + GBA_REG_BG3PC = 0x034, + GBA_REG_BG3PD = 0x036, + GBA_REG_BG3X_LO = 0x038, + GBA_REG_BG3X_HI = 0x03A, + GBA_REG_BG3Y_LO = 0x03C, + GBA_REG_BG3Y_HI = 0x03E, + GBA_REG_WIN0H = 0x040, + GBA_REG_WIN1H = 0x042, + GBA_REG_WIN0V = 0x044, + GBA_REG_WIN1V = 0x046, + GBA_REG_WININ = 0x048, + GBA_REG_WINOUT = 0x04A, + GBA_REG_MOSAIC = 0x04C, + GBA_REG_BLDCNT = 0x050, + GBA_REG_BLDALPHA = 0x052, + GBA_REG_BLDY = 0x054, // Sound - REG_SOUND1CNT_LO = 0x060, - REG_SOUND1CNT_HI = 0x062, - REG_SOUND1CNT_X = 0x064, - REG_SOUND2CNT_LO = 0x068, - REG_SOUND2CNT_HI = 0x06C, - REG_SOUND3CNT_LO = 0x070, - REG_SOUND3CNT_HI = 0x072, - REG_SOUND3CNT_X = 0x074, - REG_SOUND4CNT_LO = 0x078, - REG_SOUND4CNT_HI = 0x07C, - REG_SOUNDCNT_LO = 0x080, - REG_SOUNDCNT_HI = 0x082, - REG_SOUNDCNT_X = 0x084, - REG_SOUNDBIAS = 0x088, - REG_WAVE_RAM0_LO = 0x090, - REG_WAVE_RAM0_HI = 0x092, - REG_WAVE_RAM1_LO = 0x094, - REG_WAVE_RAM1_HI = 0x096, - REG_WAVE_RAM2_LO = 0x098, - REG_WAVE_RAM2_HI = 0x09A, - REG_WAVE_RAM3_LO = 0x09C, - REG_WAVE_RAM3_HI = 0x09E, - REG_FIFO_A_LO = 0x0A0, - REG_FIFO_A_HI = 0x0A2, - REG_FIFO_B_LO = 0x0A4, - REG_FIFO_B_HI = 0x0A6, + GBA_REG_SOUND1CNT_LO = 0x060, + GBA_REG_SOUND1CNT_HI = 0x062, + GBA_REG_SOUND1CNT_X = 0x064, + GBA_REG_SOUND2CNT_LO = 0x068, + GBA_REG_SOUND2CNT_HI = 0x06C, + GBA_REG_SOUND3CNT_LO = 0x070, + GBA_REG_SOUND3CNT_HI = 0x072, + GBA_REG_SOUND3CNT_X = 0x074, + GBA_REG_SOUND4CNT_LO = 0x078, + GBA_REG_SOUND4CNT_HI = 0x07C, + GBA_REG_SOUNDCNT_LO = 0x080, + GBA_REG_SOUNDCNT_HI = 0x082, + GBA_REG_SOUNDCNT_X = 0x084, + GBA_REG_SOUNDBIAS = 0x088, + GBA_REG_WAVE_RAM0_LO = 0x090, + GBA_REG_WAVE_RAM0_HI = 0x092, + GBA_REG_WAVE_RAM1_LO = 0x094, + GBA_REG_WAVE_RAM1_HI = 0x096, + GBA_REG_WAVE_RAM2_LO = 0x098, + GBA_REG_WAVE_RAM2_HI = 0x09A, + GBA_REG_WAVE_RAM3_LO = 0x09C, + GBA_REG_WAVE_RAM3_HI = 0x09E, + GBA_REG_FIFO_A_LO = 0x0A0, + GBA_REG_FIFO_A_HI = 0x0A2, + GBA_REG_FIFO_B_LO = 0x0A4, + GBA_REG_FIFO_B_HI = 0x0A6, // DMA - REG_DMA0SAD_LO = 0x0B0, - REG_DMA0SAD_HI = 0x0B2, - REG_DMA0DAD_LO = 0x0B4, - REG_DMA0DAD_HI = 0x0B6, - REG_DMA0CNT_LO = 0x0B8, - REG_DMA0CNT_HI = 0x0BA, - REG_DMA1SAD_LO = 0x0BC, - REG_DMA1SAD_HI = 0x0BE, - REG_DMA1DAD_LO = 0x0C0, - REG_DMA1DAD_HI = 0x0C2, - REG_DMA1CNT_LO = 0x0C4, - REG_DMA1CNT_HI = 0x0C6, - REG_DMA2SAD_LO = 0x0C8, - REG_DMA2SAD_HI = 0x0CA, - REG_DMA2DAD_LO = 0x0CC, - REG_DMA2DAD_HI = 0x0CE, - REG_DMA2CNT_LO = 0x0D0, - REG_DMA2CNT_HI = 0x0D2, - REG_DMA3SAD_LO = 0x0D4, - REG_DMA3SAD_HI = 0x0D6, - REG_DMA3DAD_LO = 0x0D8, - REG_DMA3DAD_HI = 0x0DA, - REG_DMA3CNT_LO = 0x0DC, - REG_DMA3CNT_HI = 0x0DE, + GBA_REG_DMA0SAD_LO = 0x0B0, + GBA_REG_DMA0SAD_HI = 0x0B2, + GBA_REG_DMA0DAD_LO = 0x0B4, + GBA_REG_DMA0DAD_HI = 0x0B6, + GBA_REG_DMA0CNT_LO = 0x0B8, + GBA_REG_DMA0CNT_HI = 0x0BA, + GBA_REG_DMA1SAD_LO = 0x0BC, + GBA_REG_DMA1SAD_HI = 0x0BE, + GBA_REG_DMA1DAD_LO = 0x0C0, + GBA_REG_DMA1DAD_HI = 0x0C2, + GBA_REG_DMA1CNT_LO = 0x0C4, + GBA_REG_DMA1CNT_HI = 0x0C6, + GBA_REG_DMA2SAD_LO = 0x0C8, + GBA_REG_DMA2SAD_HI = 0x0CA, + GBA_REG_DMA2DAD_LO = 0x0CC, + GBA_REG_DMA2DAD_HI = 0x0CE, + GBA_REG_DMA2CNT_LO = 0x0D0, + GBA_REG_DMA2CNT_HI = 0x0D2, + GBA_REG_DMA3SAD_LO = 0x0D4, + GBA_REG_DMA3SAD_HI = 0x0D6, + GBA_REG_DMA3DAD_LO = 0x0D8, + GBA_REG_DMA3DAD_HI = 0x0DA, + GBA_REG_DMA3CNT_LO = 0x0DC, + GBA_REG_DMA3CNT_HI = 0x0DE, // Timers - REG_TM0CNT_LO = 0x100, - REG_TM0CNT_HI = 0x102, - REG_TM1CNT_LO = 0x104, - REG_TM1CNT_HI = 0x106, - REG_TM2CNT_LO = 0x108, - REG_TM2CNT_HI = 0x10A, - REG_TM3CNT_LO = 0x10C, - REG_TM3CNT_HI = 0x10E, + GBA_REG_TM0CNT_LO = 0x100, + GBA_REG_TM0CNT_HI = 0x102, + GBA_REG_TM1CNT_LO = 0x104, + GBA_REG_TM1CNT_HI = 0x106, + GBA_REG_TM2CNT_LO = 0x108, + GBA_REG_TM2CNT_HI = 0x10A, + GBA_REG_TM3CNT_LO = 0x10C, + GBA_REG_TM3CNT_HI = 0x10E, // SIO (note: some of these are repeated) - REG_SIODATA32_LO = 0x120, - REG_SIOMULTI0 = 0x120, - REG_SIODATA32_HI = 0x122, - REG_SIOMULTI1 = 0x122, - REG_SIOMULTI2 = 0x124, - REG_SIOMULTI3 = 0x126, - REG_SIOCNT = 0x128, - REG_SIOMLT_SEND = 0x12A, - REG_SIODATA8 = 0x12A, - REG_RCNT = 0x134, - REG_JOYCNT = 0x140, - REG_JOY_RECV_LO = 0x150, - REG_JOY_RECV_HI = 0x152, - REG_JOY_TRANS_LO = 0x154, - REG_JOY_TRANS_HI = 0x156, - REG_JOYSTAT = 0x158, + GBA_REG_SIODATA32_LO = 0x120, + GBA_REG_SIOMULTI0 = 0x120, + GBA_REG_SIODATA32_HI = 0x122, + GBA_REG_SIOMULTI1 = 0x122, + GBA_REG_SIOMULTI2 = 0x124, + GBA_REG_SIOMULTI3 = 0x126, + GBA_REG_SIOCNT = 0x128, + GBA_REG_SIOMLT_SEND = 0x12A, + GBA_REG_SIODATA8 = 0x12A, + GBA_REG_RCNT = 0x134, + GBA_REG_JOYCNT = 0x140, + GBA_REG_JOY_RECV_LO = 0x150, + GBA_REG_JOY_RECV_HI = 0x152, + GBA_REG_JOY_TRANS_LO = 0x154, + GBA_REG_JOY_TRANS_HI = 0x156, + GBA_REG_JOYSTAT = 0x158, // Keypad - REG_KEYINPUT = 0x130, - REG_KEYCNT = 0x132, + GBA_REG_KEYINPUT = 0x130, + GBA_REG_KEYCNT = 0x132, // Interrupts, etc - REG_IE = 0x200, - REG_IF = 0x202, - REG_WAITCNT = 0x204, - REG_IME = 0x208, + GBA_REG_IE = 0x200, + GBA_REG_IF = 0x202, + GBA_REG_WAITCNT = 0x204, + GBA_REG_IME = 0x208, - REG_MAX = 0x20A, + GBA_REG_MAX = 0x20A, - REG_POSTFLG = 0x300, - REG_HALTCNT = 0x301, + GBA_REG_POSTFLG = 0x300, + GBA_REG_HALTCNT = 0x301, - REG_EXWAITCNT_LO = 0x800, - REG_EXWAITCNT_HI = 0x802, + GBA_REG_EXWAITCNT_LO = 0x800, + GBA_REG_EXWAITCNT_HI = 0x802, - REG_INTERNAL_EXWAITCNT_LO = 0x210, - REG_INTERNAL_EXWAITCNT_HI = 0x212, - REG_INTERNAL_MAX = 0x214, + GBA_REG_INTERNAL_EXWAITCNT_LO = 0x210, + GBA_REG_INTERNAL_EXWAITCNT_HI = 0x212, + GBA_REG_INTERNAL_MAX = 0x214, - REG_DEBUG_STRING = 0xFFF600, - REG_DEBUG_FLAGS = 0xFFF700, - REG_DEBUG_ENABLE = 0xFFF780, + GBA_REG_DEBUG_STRING = 0xFFF600, + GBA_REG_DEBUG_FLAGS = 0xFFF700, + GBA_REG_DEBUG_ENABLE = 0xFFF780, }; mLOG_DECLARE_CATEGORY(GBA_IO); diff --git a/include/mgba/internal/gba/memory.h b/include/mgba/internal/gba/memory.h index 93d565a16..f9e963d76 100644 --- a/include/mgba/internal/gba/memory.h +++ b/include/mgba/internal/gba/memory.h @@ -21,60 +21,60 @@ CXX_GUARD_START #include enum GBAMemoryRegion { - REGION_BIOS = 0x0, - REGION_WORKING_RAM = 0x2, - REGION_WORKING_IRAM = 0x3, - REGION_IO = 0x4, - REGION_PALETTE_RAM = 0x5, - REGION_VRAM = 0x6, - REGION_OAM = 0x7, - REGION_CART0 = 0x8, - REGION_CART0_EX = 0x9, - REGION_CART1 = 0xA, - REGION_CART1_EX = 0xB, - REGION_CART2 = 0xC, - REGION_CART2_EX = 0xD, - REGION_CART_SRAM = 0xE, - REGION_CART_SRAM_MIRROR = 0xF + GBA_REGION_BIOS = 0x0, + GBA_REGION_EWRAM = 0x2, + GBA_REGION_IWRAM = 0x3, + GBA_REGION_IO = 0x4, + GBA_REGION_PALETTE_RAM = 0x5, + GBA_REGION_VRAM = 0x6, + GBA_REGION_OAM = 0x7, + GBA_REGION_ROM0 = 0x8, + GBA_REGION_ROM0_EX = 0x9, + GBA_REGION_ROM1 = 0xA, + GBA_REGION_ROM1_EX = 0xB, + GBA_REGION_ROM2 = 0xC, + GBA_REGION_ROM2_EX = 0xD, + GBA_REGION_SRAM = 0xE, + GBA_REGION_SRAM_MIRROR = 0xF }; enum GBAMemoryBase { - BASE_BIOS = 0x00000000, - BASE_WORKING_RAM = 0x02000000, - BASE_WORKING_IRAM = 0x03000000, - BASE_IO = 0x04000000, - BASE_PALETTE_RAM = 0x05000000, - BASE_VRAM = 0x06000000, - BASE_OAM = 0x07000000, - BASE_CART0 = 0x08000000, - BASE_CART0_EX = 0x09000000, - BASE_CART1 = 0x0A000000, - BASE_CART1_EX = 0x0B000000, - BASE_CART2 = 0x0C000000, - BASE_CART2_EX = 0x0D000000, - BASE_CART_SRAM = 0x0E000000, - BASE_CART_SRAM_MIRROR = 0x0F000000 + GBA_BASE_BIOS = 0x00000000, + GBA_BASE_EWRAM = 0x02000000, + GBA_BASE_IWRAM = 0x03000000, + GBA_BASE_IO = 0x04000000, + GBA_BASE_PALETTE_RAM = 0x05000000, + GBA_BASE_VRAM = 0x06000000, + GBA_BASE_OAM = 0x07000000, + GBA_BASE_ROM0 = 0x08000000, + GBA_BASE_ROM0_EX = 0x09000000, + GBA_BASE_ROM1 = 0x0A000000, + GBA_BASE_ROM1_EX = 0x0B000000, + GBA_BASE_ROM2 = 0x0C000000, + GBA_BASE_ROM2_EX = 0x0D000000, + GBA_BASE_SRAM = 0x0E000000, + GBA_BASE_SRAM_MIRROR = 0x0F000000 }; enum { - SIZE_BIOS = 0x00004000, - SIZE_WORKING_RAM = 0x00040000, - SIZE_WORKING_IRAM = 0x00008000, - SIZE_IO = 0x00000400, - SIZE_PALETTE_RAM = 0x00000400, - SIZE_VRAM = 0x00018000, - SIZE_OAM = 0x00000400, - SIZE_CART0 = 0x02000000, - SIZE_CART1 = 0x02000000, - SIZE_CART2 = 0x02000000, - SIZE_CART_SRAM = 0x00008000, - SIZE_CART_SRAM512 = 0x00010000, - SIZE_CART_FLASH512 = 0x00010000, - SIZE_CART_FLASH1M = 0x00020000, - SIZE_CART_EEPROM = 0x00002000, - SIZE_CART_EEPROM512 = 0x00000200, + GBA_SIZE_BIOS = 0x00004000, + GBA_SIZE_EWRAM = 0x00040000, + GBA_SIZE_IWRAM = 0x00008000, + GBA_SIZE_IO = 0x00000400, + GBA_SIZE_PALETTE_RAM = 0x00000400, + GBA_SIZE_VRAM = 0x00018000, + GBA_SIZE_OAM = 0x00000400, + GBA_SIZE_ROM0 = 0x02000000, + GBA_SIZE_ROM1 = 0x02000000, + GBA_SIZE_ROM2 = 0x02000000, + GBA_SIZE_SRAM = 0x00008000, + GBA_SIZE_SRAM512 = 0x00010000, + GBA_SIZE_FLASH512 = 0x00010000, + GBA_SIZE_FLASH1M = 0x00020000, + GBA_SIZE_EEPROM = 0x00002000, + GBA_SIZE_EEPROM512 = 0x00000200, - SIZE_AGB_PRINT = 0x10000 + GBA_SIZE_AGB_PRINT = 0x10000 }; enum { @@ -147,6 +147,7 @@ void GBAMemoryInit(struct GBA* gba); void GBAMemoryDeinit(struct GBA* gba); void GBAMemoryReset(struct GBA* gba); +void GBAMemoryClearAGBPrint(struct GBA* gba); uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter); uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter); diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index 44266c101..969ffed64 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -42,6 +42,8 @@ struct GBAVideoSoftwareBackground { uint16_t mapCache[64]; uint32_t flags; uint32_t objwinFlags; + int objwinForceEnable; + bool objwinOnly; bool variant; int32_t offsetX; int32_t offsetY; @@ -136,9 +138,9 @@ struct GBAVideoSoftwareRenderer { int16_t objOffsetY; uint32_t scanlineDirty[5]; - uint16_t nextIo[REG_SOUND1CNT_LO >> 1]; + uint16_t nextIo[GBA_REG(SOUND1CNT_LO)]; struct ScanlineCache { - uint16_t io[REG_SOUND1CNT_LO >> 1]; + uint16_t io[GBA_REG(SOUND1CNT_LO)]; int32_t scale[2][2]; } cache[GBA_VIDEO_VERTICAL_PIXELS]; int nextY; diff --git a/include/mgba/internal/gba/serialize.h b/include/mgba/internal/gba/serialize.h index ec44dc8fd..25bd170d6 100644 --- a/include/mgba/internal/gba/serialize.h +++ b/include/mgba/internal/gba/serialize.h @@ -407,12 +407,12 @@ struct GBASerializedState { uint32_t reserved[12]; - uint16_t io[SIZE_IO >> 1]; - uint16_t pram[SIZE_PALETTE_RAM >> 1]; - uint16_t oam[SIZE_OAM >> 1]; - uint16_t vram[SIZE_VRAM >> 1]; - uint8_t iwram[SIZE_WORKING_IRAM]; - uint8_t wram[SIZE_WORKING_RAM]; + uint16_t io[GBA_SIZE_IO >> 1]; + uint16_t pram[GBA_SIZE_PALETTE_RAM >> 1]; + uint16_t oam[GBA_SIZE_OAM >> 1]; + uint16_t vram[GBA_SIZE_VRAM >> 1]; + uint8_t iwram[GBA_SIZE_IWRAM]; + uint8_t wram[GBA_SIZE_EWRAM]; }; static_assert(sizeof(struct GBASerializedState) == 0x61000, "GBA savestate struct sized wrong"); diff --git a/include/mgba/internal/script/types.h b/include/mgba/internal/script/types.h new file mode 100644 index 000000000..fde5ce0ae --- /dev/null +++ b/include/mgba/internal/script/types.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef M_SCRIPT_TYPES_INTERNAL_H +#define M_SCRIPT_TYPES_INTERNAL_H + +#include + +CXX_GUARD_START + +struct Table; +void mScriptContextGetInputTypes(struct Table*); + +void mScriptTypeAdd(struct Table*, const struct mScriptType* type); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/internal/sm83/decoder.h b/include/mgba/internal/sm83/decoder.h index 14104ef48..2e3761bc0 100644 --- a/include/mgba/internal/sm83/decoder.h +++ b/include/mgba/internal/sm83/decoder.h @@ -106,6 +106,7 @@ struct SM83InstructionInfo { size_t SM83Decode(uint8_t opcode, struct SM83InstructionInfo* info); int SM83Disassemble(struct SM83InstructionInfo* info, uint16_t pc, char* buffer, int blen); +int SM83InstructionLength(uint8_t opcode); CXX_GUARD_END diff --git a/include/mgba/script.h b/include/mgba/script.h new file mode 100644 index 000000000..747dfedc1 --- /dev/null +++ b/include/mgba/script.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef M_SCRIPT_H +#define M_SCRIPT_H + +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/include/mgba/script/base.h b/include/mgba/script/base.h new file mode 100644 index 000000000..4e8bbf168 --- /dev/null +++ b/include/mgba/script/base.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef M_SCRIPT_BASE_H +#define M_SCRIPT_BASE_H + +#include + +CXX_GUARD_START + +#include +#include + +mSCRIPT_DECLARE_STRUCT(mImage) + +struct mScriptContext; +void mScriptContextAttachImage(struct mScriptContext* context); +void mScriptContextAttachStdlib(struct mScriptContext* context); +void mScriptContextAttachSocket(struct mScriptContext* context); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/script/canvas.h b/include/mgba/script/canvas.h new file mode 100644 index 000000000..e48cd4e5d --- /dev/null +++ b/include/mgba/script/canvas.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef M_SCRIPT_CANVAS_H +#define M_SCRIPT_CANVAS_H + +#include + +CXX_GUARD_START + +#include +#include + +struct VideoBackend; +void mScriptContextAttachCanvas(struct mScriptContext* context); +void mScriptCanvasUpdate(struct mScriptContext* context); +void mScriptCanvasUpdateBackend(struct mScriptContext* context, struct VideoBackend*); +void mScriptCanvasSetInternalScale(struct mScriptContext* context, unsigned scale); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/script/context.h b/include/mgba/script/context.h index 99eefe069..25628d785 100644 --- a/include/mgba/script/context.h +++ b/include/mgba/script/context.h @@ -15,7 +15,7 @@ CXX_GUARD_START #include #include -#define mSCRIPT_KV_PAIR(KEY, VALUE) { #KEY, VALUE } +#define mSCRIPT_KV_PAIR(KEY, VALUE) { #KEY, (struct mScriptValue*) VALUE } #define mSCRIPT_CONSTANT_PAIR(NS, CONST) { #CONST, mScriptValueCreateFromSInt(NS ## _ ## CONST) } #define mSCRIPT_KV_SENTINEL { NULL, NULL } @@ -36,6 +36,7 @@ struct mScriptContext { uint32_t nextCallbackId; struct mScriptValue* constants; struct Table docstrings; + int threadDepth; }; struct mScriptEngine2 { @@ -89,14 +90,14 @@ uint32_t mScriptContextSetWeakref(struct mScriptContext*, struct mScriptValue* v struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value); struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value); void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref); +void mScriptContextDisownWeakref(struct mScriptContext*, uint32_t weakref); -void mScriptContextAttachStdlib(struct mScriptContext* context); -void mScriptContextAttachSocket(struct mScriptContext* context); void mScriptContextExportConstants(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* constants); void mScriptContextExportNamespace(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* value); -void mScriptContextTriggerCallback(struct mScriptContext*, const char* callback); +void mScriptContextTriggerCallback(struct mScriptContext*, const char* callback, struct mScriptList* args); uint32_t mScriptContextAddCallback(struct mScriptContext*, const char* callback, struct mScriptValue* value); +uint32_t mScriptContextAddOneshot(struct mScriptContext*, const char* callback, struct mScriptValue* value); void mScriptContextRemoveCallback(struct mScriptContext*, uint32_t cbid); void mScriptContextSetDocstring(struct mScriptContext*, const char* key, const char* docstring); @@ -110,6 +111,12 @@ struct VFile; bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf); bool mScriptContextLoadFile(struct mScriptContext*, const char* path); +struct mScriptContext* mScriptActiveContext(void); +bool mScriptContextActivate(struct mScriptContext*); +void mScriptContextDeactivate(struct mScriptContext*); + +bool mScriptContextInvoke(struct mScriptContext*, const struct mScriptValue* fn, struct mScriptFrame* frame); + bool mScriptInvoke(const struct mScriptValue* fn, struct mScriptFrame* frame); CXX_GUARD_END diff --git a/include/mgba/script/input.h b/include/mgba/script/input.h new file mode 100644 index 000000000..fea9f3320 --- /dev/null +++ b/include/mgba/script/input.h @@ -0,0 +1,272 @@ +/* Copyright (c) 2013-2022 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/. */ +#ifndef M_SCRIPT_INPUT_H +#define M_SCRIPT_INPUT_H + +#include + +#include +#include + +CXX_GUARD_START + +enum mScriptEventType { + mSCRIPT_EV_TYPE_NONE = 0, + mSCRIPT_EV_TYPE_KEY, + mSCRIPT_EV_TYPE_MOUSE_BUTTON, + mSCRIPT_EV_TYPE_MOUSE_MOVE, + mSCRIPT_EV_TYPE_MOUSE_WHEEL, + mSCRIPT_EV_TYPE_GAMEPAD_BUTTON, + mSCRIPT_EV_TYPE_GAMEPAD_HAT, + mSCRIPT_EV_TYPE_TRIGGER, + mSCRIPT_EV_TYPE_MAX +}; + +enum mScriptInputState { + mSCRIPT_INPUT_STATE_UP = 0, + mSCRIPT_INPUT_STATE_DOWN = 1, + mSCRIPT_INPUT_STATE_HELD = 2, +}; + +enum mScriptInputDirection { + mSCRIPT_INPUT_DIR_NONE = 0, + + mSCRIPT_INPUT_DIR_NORTH = 1, + mSCRIPT_INPUT_DIR_EAST = 2, + mSCRIPT_INPUT_DIR_SOUTH = 4, + mSCRIPT_INPUT_DIR_WEST = 8, + + mSCRIPT_INPUT_DIR_UP = mSCRIPT_INPUT_DIR_NORTH, + mSCRIPT_INPUT_DIR_RIGHT = mSCRIPT_INPUT_DIR_EAST, + mSCRIPT_INPUT_DIR_DOWN = mSCRIPT_INPUT_DIR_SOUTH, + mSCRIPT_INPUT_DIR_LEFT = mSCRIPT_INPUT_DIR_WEST, + + mSCRIPT_INPUT_DIR_NORTHEAST = mSCRIPT_INPUT_DIR_NORTH | mSCRIPT_INPUT_DIR_EAST, + mSCRIPT_INPUT_DIR_NORTHWEST = mSCRIPT_INPUT_DIR_NORTH | mSCRIPT_INPUT_DIR_WEST, + mSCRIPT_INPUT_DIR_SOUTHEAST = mSCRIPT_INPUT_DIR_SOUTH | mSCRIPT_INPUT_DIR_EAST, + mSCRIPT_INPUT_DIR_SOUTHWEST = mSCRIPT_INPUT_DIR_SOUTH | mSCRIPT_INPUT_DIR_WEST, +}; + +enum mScriptKeyModifier { + mSCRIPT_KMOD_NONE = 0, + + mSCRIPT_KMOD_LSHIFT = 0x1, + mSCRIPT_KMOD_RSHIFT = 0x2, + mSCRIPT_KMOD_SHIFT = 0x3, + + mSCRIPT_KMOD_LCONTROL = 0x4, + mSCRIPT_KMOD_RCONTROL = 0x8, + mSCRIPT_KMOD_CONTROL = 0xC, + + mSCRIPT_KMOD_LALT = 0x10, + mSCRIPT_KMOD_RALT = 0x20, + mSCRIPT_KMOD_ALT = 0x30, + + mSCRIPT_KMOD_LSUPER = 0x40, + mSCRIPT_KMOD_RSUPER = 0x80, + mSCRIPT_KMOD_SUPER = 0xC0, + + mSCRIPT_KMOD_CAPS_LOCK = 0x100, + mSCRIPT_KMOD_NUM_LOCK = 0x200, + mSCRIPT_KMOD_SCROLL_LOCK = 0x400, +}; + +#define mSCRIPT_KEYBASE 0x800000 + +enum mScriptKey { + mSCRIPT_KEY_NONE = 0, + + mSCRIPT_KEY_BACKSPACE = 0x000008, + mSCRIPT_KEY_TAB = 0x000009, + mSCRIPT_KEY_ENTER = 0x00000A, + mSCRIPT_KEY_ESCAPE = 0x00001B, + mSCRIPT_KEY_DELETE = 0x00007F, + + mSCRIPT_KEY_F1 = mSCRIPT_KEYBASE | 1, + mSCRIPT_KEY_F2, + mSCRIPT_KEY_F3, + mSCRIPT_KEY_F4, + mSCRIPT_KEY_F5, + mSCRIPT_KEY_F6, + mSCRIPT_KEY_F7, + mSCRIPT_KEY_F8, + mSCRIPT_KEY_F9, + mSCRIPT_KEY_F10, + mSCRIPT_KEY_F11, + mSCRIPT_KEY_F12, + mSCRIPT_KEY_F13, + mSCRIPT_KEY_F14, + mSCRIPT_KEY_F15, + mSCRIPT_KEY_F16, + mSCRIPT_KEY_F17, + mSCRIPT_KEY_F18, + mSCRIPT_KEY_F19, + mSCRIPT_KEY_F20, + mSCRIPT_KEY_F21, + mSCRIPT_KEY_F22, + mSCRIPT_KEY_F23, + mSCRIPT_KEY_F24, + + mSCRIPT_KEY_UP = mSCRIPT_KEYBASE | 0x20, + mSCRIPT_KEY_RIGHT, + mSCRIPT_KEY_DOWN, + mSCRIPT_KEY_LEFT, + mSCRIPT_KEY_PAGE_UP, + mSCRIPT_KEY_PAGE_DOWN, + mSCRIPT_KEY_HOME, + mSCRIPT_KEY_END, + mSCRIPT_KEY_INSERT, + mSCRIPT_KEY_BREAK, + mSCRIPT_KEY_CLEAR, + mSCRIPT_KEY_PRINT_SCREEN, + mSCRIPT_KEY_SYSRQ, + mSCRIPT_KEY_MENU, + mSCRIPT_KEY_HELP, + + mSCRIPT_KEY_LSHIFT = mSCRIPT_KEYBASE | 0x30, + mSCRIPT_KEY_RSHIFT, + mSCRIPT_KEY_SHIFT, + mSCRIPT_KEY_LCONTROL, + mSCRIPT_KEY_RCONTROL, + mSCRIPT_KEY_CONTROL, + mSCRIPT_KEY_LALT, + mSCRIPT_KEY_RALT, + mSCRIPT_KEY_ALT, + mSCRIPT_KEY_LSUPER, + mSCRIPT_KEY_RSUPER, + mSCRIPT_KEY_SUPER, + mSCRIPT_KEY_CAPS_LOCK, + mSCRIPT_KEY_NUM_LOCK, + mSCRIPT_KEY_SCROLL_LOCK, + + mSCRIPT_KEY_KP_0 = mSCRIPT_KEYBASE | 0x40, + mSCRIPT_KEY_KP_1, + mSCRIPT_KEY_KP_2, + mSCRIPT_KEY_KP_3, + mSCRIPT_KEY_KP_4, + mSCRIPT_KEY_KP_5, + mSCRIPT_KEY_KP_6, + mSCRIPT_KEY_KP_7, + mSCRIPT_KEY_KP_8, + mSCRIPT_KEY_KP_9, + mSCRIPT_KEY_KP_PLUS, + mSCRIPT_KEY_KP_MINUS, + mSCRIPT_KEY_KP_MULTIPLY, + mSCRIPT_KEY_KP_DIVIDE, + mSCRIPT_KEY_KP_COMMA, + mSCRIPT_KEY_KP_POINT, + mSCRIPT_KEY_KP_ENTER, +}; + +enum mScriptMouseButton { + mSCRIPT_MOUSE_BUTTON_PRIMARY = 0, + mSCRIPT_MOUSE_BUTTON_SECONDARY = 1, + mSCRIPT_MOUSE_BUTTON_MIDDLE = 2, +}; + +struct mScriptEvent { + int32_t type; + int32_t reserved; + uint64_t seq; +}; + +struct mScriptKeyEvent { + struct mScriptEvent d; + uint8_t state; + uint16_t modifiers; + uint32_t key; +}; + +struct mScriptMouseButtonEvent { + struct mScriptEvent d; + uint8_t mouse; + uint8_t context; + uint8_t state; + uint8_t button; +}; + +struct mScriptMouseMoveEvent { + struct mScriptEvent d; + uint8_t mouse; + uint8_t context; + int32_t x; + int32_t y; +}; + +struct mScriptMouseWheelEvent { + struct mScriptEvent d; + uint8_t mouse; + int16_t x; + int16_t y; +}; + +struct mScriptGamepadButtonEvent { + struct mScriptEvent d; + uint8_t state; + uint8_t pad; + uint16_t button; +}; + +struct mScriptGamepadHatEvent { + struct mScriptEvent d; + uint8_t pad; + uint8_t hat; + uint8_t direction; +}; + +struct mScriptTriggerEvent { + struct mScriptEvent d; + uint8_t trigger; + bool state; +}; + +struct mScriptGamepad { + unsigned pad; + + char visibleName[128]; + char internalName[64]; + + struct mScriptList axes; + struct mScriptList buttons; + struct mScriptList hats; +}; + +mSCRIPT_DECLARE_STRUCT(mScriptEvent); +mSCRIPT_DECLARE_STRUCT(mScriptKeyEvent); +mSCRIPT_DECLARE_STRUCT(mScriptMouseButtonEvent); +mSCRIPT_DECLARE_STRUCT(mScriptMouseMoveEvent); +mSCRIPT_DECLARE_STRUCT(mScriptMouseWheelEvent); +mSCRIPT_DECLARE_STRUCT(mScriptGamepadButtonEvent); +mSCRIPT_DECLARE_STRUCT(mScriptGamepadHatEvent); +mSCRIPT_DECLARE_STRUCT(mScriptSensorEvent); +mSCRIPT_DECLARE_STRUCT(mScriptTriggerEvent); + +mSCRIPT_DECLARE_STRUCT(mScriptGamepad); + +void mScriptContextAttachInput(struct mScriptContext* context); + +void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*); +void mScriptContextClearKeys(struct mScriptContext*); + +int mScriptContextGamepadAttach(struct mScriptContext*, struct mScriptGamepad*); +bool mScriptContextGamepadDetach(struct mScriptContext*, int pad); +struct mScriptGamepad* mScriptContextGamepadLookup(struct mScriptContext*, int pad); + +void mScriptGamepadInit(struct mScriptGamepad*); +void mScriptGamepadDeinit(struct mScriptGamepad*); +void mScriptGamepadSetAxisCount(struct mScriptGamepad*, unsigned); +void mScriptGamepadSetButtonCount(struct mScriptGamepad*, unsigned); +void mScriptGamepadSetHatCount(struct mScriptGamepad*, unsigned); +void mScriptGamepadSetAxis(struct mScriptGamepad*, unsigned, int16_t value); +void mScriptGamepadSetButton(struct mScriptGamepad*, unsigned, bool down); +void mScriptGamepadSetHat(struct mScriptGamepad*, unsigned, int direction); +int16_t mScriptGamepadGetAxis(struct mScriptGamepad*, unsigned); +bool mScriptGamepadGetButton(struct mScriptGamepad*, unsigned); +int mScriptGamepadGetHat(struct mScriptGamepad*, unsigned); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/script/macros.h b/include/mgba/script/macros.h index 42710f9e8..4acf7591a 100644 --- a/include/mgba/script/macros.h +++ b/include/mgba/script/macros.h @@ -15,11 +15,11 @@ CXX_GUARD_START do { \ struct mScriptValue* _val = mScriptListGetPointer(STACK, mScriptListSize(STACK) - 1); \ bool deref = true; \ - if (!(mSCRIPT_TYPE_CMP(TYPE, _val->type))) { \ + if (!(mSCRIPT_TYPE_CMP(TYPE, _val))) { \ if (_val->type->base == mSCRIPT_TYPE_WRAPPER) { \ _val = mScriptValueUnwrap(_val); \ deref = false; \ - if (!(mSCRIPT_TYPE_CMP(TYPE, _val->type))) { \ + if (!(mSCRIPT_TYPE_CMP(TYPE, _val))) { \ return false; \ } \ } else { \ @@ -73,7 +73,8 @@ CXX_GUARD_START #define mSCRIPT_PREFIX_8(PREFIX, T0, T1, T2, T3, T4, T5, T6, T7) PREFIX ## T0, PREFIX ## T1, PREFIX ## T2, PREFIX ## T3, PREFIX ## T4, PREFIX ## T5, PREFIX ## T6, PREFIX ## T7 #define mSCRIPT_PREFIX_N(N) mSCRIPT_PREFIX_ ## N -#define _mSCRIPT_FIELD_NAME(V) (V)->name +#define _mSCRIPT_FIELD_NAME(V) (V)->type->name +#define _mSCRIPT_WRAPPED_FIELD_NAME(V) (V)->value.wrapped->type->name #define _mSCRIPT_CALL_VOID(FUNCTION, NPARAMS) FUNCTION(_mCAT(mSCRIPT_ARG_NAMES_, NPARAMS)) #define _mSCRIPT_CALL(RETURN, FUNCTION, NPARAMS) \ @@ -212,20 +213,30 @@ CXX_GUARD_START } \ }, -#define mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(STRUCT, TYPE, EXPORTED_NAME, NAME) { \ +#define _mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, EXPORTED_NAME, NAME, RO) { \ .type = mSCRIPT_CLASS_INIT_INSTANCE_MEMBER, \ .info = { \ .member = { \ .name = #EXPORTED_NAME, \ .type = mSCRIPT_TYPE_MS_ ## TYPE, \ - .offset = offsetof(struct STRUCT, NAME) \ + .offset = offsetof(struct STRUCT, NAME), \ + .readonly = RO \ } \ } \ }, +#define mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(STRUCT, TYPE, EXPORTED_NAME, NAME) \ + _mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, EXPORTED_NAME, NAME, false) + +#define mSCRIPT_DEFINE_STRUCT_CONST_MEMBER_NAMED(STRUCT, TYPE, EXPORTED_NAME, NAME) \ + _mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, EXPORTED_NAME, NAME, true) + #define mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, NAME) \ mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(STRUCT, TYPE, NAME, NAME) +#define mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(STRUCT, TYPE, NAME) \ + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER_NAMED(STRUCT, TYPE, NAME, NAME) + #define mSCRIPT_DEFINE_INHERIT(PARENT) { \ .type = mSCRIPT_CLASS_INIT_INHERIT, \ .info = { \ @@ -393,6 +404,9 @@ CXX_GUARD_START static const struct mScriptValue _mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME[mSCRIPT_PARAMS_MAX]; \ _mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME, S, 0, 0, NPARAMS, _mIDENT(_mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME), __VA_ARGS__) \ +#define mSCRIPT_DEFINE_FUNCTION_BINDING_DEFAULTS(NAME) \ + static const struct mScriptValue _bindingDefaults_ ## NAME[mSCRIPT_PARAMS_MAX] = { + #define mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(TYPE, NAME) \ static const struct mScriptValue _mSTStructBindingDefaults_ ## TYPE ## _ ## NAME[mSCRIPT_PARAMS_MAX] = { \ mSCRIPT_NO_DEFAULT, @@ -423,7 +437,7 @@ CXX_GUARD_START #define mSCRIPT_DEFINE_STRUCT_DEINIT(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, _deinit) #define mSCRIPT_DEFINE_STRUCT_DEINIT_NAMED(TYPE, NAME) _mSCRIPT_DEFINE_STRUCT_BINDING(DEINIT, TYPE, _deinit, NAME) #define mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(GET, TYPE, _get, _get) -#define mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(SET, TYPE, _set, _set) +#define mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TYPE, SETTER) _mSCRIPT_DEFINE_STRUCT_BINDING(SET, TYPE, SETTER, SETTER) #define mSCRIPT_DEFINE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME) mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(doc_ ## TYPE, NAME, NAME) @@ -439,7 +453,7 @@ CXX_GUARD_START #define mSCRIPT_DEFINE_END { .type = mSCRIPT_CLASS_INIT_END } } } -#define _mSCRIPT_BIND_FUNCTION(NAME, NRET, RETURN, NPARAMS, ...) \ +#define _mSCRIPT_BIND_FUNCTION(NAME, NRET, RETURN, DEFAULTS, NPARAMS, ...) \ static struct mScriptFunction _function_ ## NAME = { \ .call = _binding_ ## NAME \ }; \ @@ -456,6 +470,7 @@ CXX_GUARD_START .count = NPARAMS, \ .entries = { _mCALL(_mIF0_ ## NPARAMS, 0) _mCALL(mSCRIPT_PREFIX_ ## NPARAMS, mSCRIPT_TYPE_MS_, _mEVEN_ ## NPARAMS(__VA_ARGS__)) }, \ .names = { _mCALL(_mIF0_ ## NPARAMS, 0) _mCALL(_mCALL_ ## NPARAMS, _mSTRINGIFY, _mODD_ ## NPARAMS(__VA_ARGS__)) }, \ + .defaults = DEFAULTS, \ }, \ .returnType = { \ .count = NRET, \ @@ -472,7 +487,7 @@ CXX_GUARD_START } \ } -#define mSCRIPT_BIND_FUNCTION(NAME, RETURN, FUNCTION, NPARAMS, ...) \ +#define _mSCRIPT_BIND_N_FUNCTION(NAME, RETURN, FUNCTION, DEFAULTS, NPARAMS, ...) \ static bool _binding_ ## NAME(struct mScriptFrame* frame, void* ctx) { \ UNUSED(ctx); \ _mCALL(mSCRIPT_POP_ ## NPARAMS, &frame->arguments, _mEVEN_ ## NPARAMS(__VA_ARGS__)); \ @@ -482,9 +497,9 @@ CXX_GUARD_START _mSCRIPT_CALL(RETURN, FUNCTION, NPARAMS); \ return true; \ } \ - _mSCRIPT_BIND_FUNCTION(NAME, 1, mSCRIPT_TYPE_MS_ ## RETURN, NPARAMS, __VA_ARGS__) + _mSCRIPT_BIND_FUNCTION(NAME, 1, mSCRIPT_TYPE_MS_ ## RETURN, DEFAULTS, NPARAMS, __VA_ARGS__) -#define mSCRIPT_BIND_VOID_FUNCTION(NAME, FUNCTION, NPARAMS, ...) \ +#define _mSCRIPT_BIND_VOID_FUNCTION(NAME, FUNCTION, DEFAULTS, NPARAMS, ...) \ static bool _binding_ ## NAME(struct mScriptFrame* frame, void* ctx) { \ UNUSED(ctx); \ _mCALL(mSCRIPT_POP_ ## NPARAMS, &frame->arguments, _mEVEN_ ## NPARAMS(__VA_ARGS__)); \ @@ -494,7 +509,21 @@ CXX_GUARD_START _mSCRIPT_CALL_VOID(FUNCTION, NPARAMS); \ return true; \ } \ - _mSCRIPT_BIND_FUNCTION(NAME, 0, 0, NPARAMS, __VA_ARGS__) + _mSCRIPT_BIND_FUNCTION(NAME, 0, 0, NULL, NPARAMS, __VA_ARGS__) + +#define mSCRIPT_BIND_FUNCTION(NAME, RETURN, FUNCTION, NPARAMS, ...) \ + _mSCRIPT_BIND_N_FUNCTION(NAME, RETURN, FUNCTION, NULL, NPARAMS, __VA_ARGS__) + +#define mSCRIPT_BIND_VOID_FUNCTION(NAME, FUNCTION, NPARAMS, ...) \ + _mSCRIPT_BIND_VOID_FUNCTION(NAME, FUNCTION, NULL, NPARAMS, __VA_ARGS__) + +#define mSCRIPT_BIND_FUNCTION_WITH_DEFAULTS(NAME, RETURN, FUNCTION, NPARAMS, ...) \ + static const struct mScriptValue _bindingDefaults_ ## NAME[mSCRIPT_PARAMS_MAX]; \ + _mSCRIPT_BIND_N_FUNCTION(NAME, RETURN, FUNCTION, _mIDENT(_bindingDefaults_ ## NAME), NPARAMS, __VA_ARGS__) + +#define mSCRIPT_BIND_VOID_FUNCTION_WITH_DEFAULTS(NAME, FUNCTION, NPARAMS, ...) \ + static const struct mScriptValue _bindingDefaults_ ## _ ## NAME[mSCRIPT_PARAMS_MAX]; \ + _mSCRIPT_BIND_VOID_FUNCTION(NAME, FUNCTION, _mIDENT(_bindingDefaults_ ## NAME), NPARAMS, __VA_ARGS__) #define _mSCRIPT_DEFINE_DOC_FUNCTION(SCOPE, NAME, NRET, RETURN, NPARAMS, ...) \ static const struct mScriptType _mScriptDocType_ ## NAME = { \ diff --git a/include/mgba/script/storage.h b/include/mgba/script/storage.h new file mode 100644 index 000000000..629158e83 --- /dev/null +++ b/include/mgba/script/storage.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2013-2023 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/. */ +#ifndef M_SCRIPT_STORAGE_H +#define M_SCRIPT_STORAGE_H + +#include + +CXX_GUARD_START + +#include +#include + +struct VFile; +void mScriptContextAttachStorage(struct mScriptContext* context); +void mScriptStorageFlushAll(struct mScriptContext* context); + +bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucket); +bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucket, struct VFile* vf); +bool mScriptStorageLoadBucket(struct mScriptContext* context, const char* bucket); +bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* bucket, struct VFile* vf); +void mScriptStorageGetBucketPath(const char* bucket, char* out); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/script/types.h b/include/mgba/script/types.h index 470ed40ce..1475f1a6e 100644 --- a/include/mgba/script/types.h +++ b/include/mgba/script/types.h @@ -35,16 +35,17 @@ CXX_GUARD_START #define mSCRIPT_TYPE_C_PTR void* #define mSCRIPT_TYPE_C_CPTR const void* #define mSCRIPT_TYPE_C_LIST struct mScriptList* -#define mSCRIPT_TYPE_C_TABLE Table* +#define mSCRIPT_TYPE_C_TABLE struct Table* #define mSCRIPT_TYPE_C_WRAPPER struct mScriptValue* #define mSCRIPT_TYPE_C_WEAKREF uint32_t +#define mSCRIPT_TYPE_C_NUL void* #define mSCRIPT_TYPE_C_S(STRUCT) struct STRUCT* #define mSCRIPT_TYPE_C_CS(STRUCT) const struct STRUCT* -#define mSCRIPT_TYPE_C_S_METHOD(STRUCT, NAME) _mSTStructFunctionType_ ## STRUCT ## _ ## NAME #define mSCRIPT_TYPE_C_PS(X) void #define mSCRIPT_TYPE_C_PCS(X) void #define mSCRIPT_TYPE_C_WSTR struct mScriptValue* #define mSCRIPT_TYPE_C_WLIST struct mScriptValue* +#define mSCRIPT_TYPE_C_WTABLE struct mScriptValue* #define mSCRIPT_TYPE_C_W(X) struct mScriptValue* #define mSCRIPT_TYPE_C_CW(X) const struct mScriptValue* @@ -66,16 +67,18 @@ CXX_GUARD_START #define mSCRIPT_TYPE_FIELD_TABLE table #define mSCRIPT_TYPE_FIELD_WRAPPER opaque #define mSCRIPT_TYPE_FIELD_WEAKREF u32 +#define mSCRIPT_TYPE_FIELD_NUL opaque #define mSCRIPT_TYPE_FIELD_S(STRUCT) opaque #define mSCRIPT_TYPE_FIELD_CS(STRUCT) copaque -#define mSCRIPT_TYPE_FIELD_S_METHOD(STRUCT, NAME) copaque #define mSCRIPT_TYPE_FIELD_PS(STRUCT) opaque #define mSCRIPT_TYPE_FIELD_PCS(STRUCT) copaque #define mSCRIPT_TYPE_FIELD_WSTR opaque #define mSCRIPT_TYPE_FIELD_WLIST opaque +#define mSCRIPT_TYPE_FIELD_WTABLE opaque #define mSCRIPT_TYPE_FIELD_W(TYPE) opaque #define mSCRIPT_TYPE_FIELD_CW(TYPE) opaque +#define mSCRIPT_TYPE_MS_VOID (&mSTVoid) #define mSCRIPT_TYPE_MS_S8 (&mSTSInt8) #define mSCRIPT_TYPE_MS_U8 (&mSTUInt8) #define mSCRIPT_TYPE_MS_S16 (&mSTSInt16) @@ -93,40 +96,70 @@ CXX_GUARD_START #define mSCRIPT_TYPE_MS_TABLE (&mSTTable) #define mSCRIPT_TYPE_MS_WRAPPER (&mSTWrapper) #define mSCRIPT_TYPE_MS_WEAKREF (&mSTWeakref) +#define mSCRIPT_TYPE_MS_NUL mSCRIPT_TYPE_MS_VOID #define mSCRIPT_TYPE_MS_S(STRUCT) (&mSTStruct_ ## STRUCT) #define mSCRIPT_TYPE_MS_CS(STRUCT) (&mSTStructConst_ ## STRUCT) -#define mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME) (&_mSTStructBindingType_ ## STRUCT ## _ ## NAME) #define mSCRIPT_TYPE_MS_PS(STRUCT) (&mSTStructPtr_ ## STRUCT) -#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructConstPtr_ ## STRUCT) +#define mSCRIPT_TYPE_MS_PCS(STRUCT) (&mSTStructPtrConst_ ## STRUCT) #define mSCRIPT_TYPE_MS_WSTR (&mSTStringWrapper) #define mSCRIPT_TYPE_MS_WLIST (&mSTListWrapper) +#define mSCRIPT_TYPE_MS_WTABLE (&mSTTableWrapper) #define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE) #define mSCRIPT_TYPE_MS_CW(TYPE) (&mSTWrapperConst_ ## TYPE) #define mSCRIPT_TYPE_MS_DS(STRUCT) (&mSTStruct_doc_ ## STRUCT) -#define mSCRIPT_TYPE_CMP_GENERIC(TYPE0, TYPE1) (TYPE0 == TYPE1) -#define mSCRIPT_TYPE_CMP_U8(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U8, TYPE) -#define mSCRIPT_TYPE_CMP_S8(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S8, TYPE) -#define mSCRIPT_TYPE_CMP_U16(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U16, TYPE) -#define mSCRIPT_TYPE_CMP_S16(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S16, TYPE) -#define mSCRIPT_TYPE_CMP_U32(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U32, TYPE) -#define mSCRIPT_TYPE_CMP_S32(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S32, TYPE) -#define mSCRIPT_TYPE_CMP_F32(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_F32, TYPE) -#define mSCRIPT_TYPE_CMP_U64(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U64, TYPE) -#define mSCRIPT_TYPE_CMP_S64(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S64, TYPE) -#define mSCRIPT_TYPE_CMP_F64(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_F64, TYPE) -#define mSCRIPT_TYPE_CMP_BOOL(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_BOOL, TYPE) -#define mSCRIPT_TYPE_CMP_STR(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_STR, TYPE) -#define mSCRIPT_TYPE_CMP_CHARP(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_CHARP, TYPE) -#define mSCRIPT_TYPE_CMP_LIST(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_LIST, TYPE) -#define mSCRIPT_TYPE_CMP_PTR(TYPE) ((TYPE)->base >= mSCRIPT_TYPE_OPAQUE) -#define mSCRIPT_TYPE_CMP_WRAPPER(TYPE) (true) +#define mSCRIPT_TYPE_CMP_GENERIC(TYPE, V) (TYPE == (V)->type) +#define mSCRIPT_TYPE_CMP_U8(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U8, V) +#define mSCRIPT_TYPE_CMP_S8(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S8, V) +#define mSCRIPT_TYPE_CMP_U16(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U16, V) +#define mSCRIPT_TYPE_CMP_S16(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S16, V) +#define mSCRIPT_TYPE_CMP_U32(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U32, V) +#define mSCRIPT_TYPE_CMP_S32(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S32, V) +#define mSCRIPT_TYPE_CMP_F32(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_F32, V) +#define mSCRIPT_TYPE_CMP_U64(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U64, V) +#define mSCRIPT_TYPE_CMP_S64(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_S64, V) +#define mSCRIPT_TYPE_CMP_F64(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_F64, V) +#define mSCRIPT_TYPE_CMP_BOOL(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_BOOL, V) +#define mSCRIPT_TYPE_CMP_STR(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_STR, V) +#define mSCRIPT_TYPE_CMP_CHARP(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_CHARP, V) +#define mSCRIPT_TYPE_CMP_LIST(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_LIST, V) +#define mSCRIPT_TYPE_CMP_TABLE(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_TABLE, V) +#define mSCRIPT_TYPE_CMP_PTR(V) ((V)->type->base >= mSCRIPT_TYPE_OPAQUE) +#define mSCRIPT_TYPE_CMP_WRAPPER(V) (true) +#define mSCRIPT_TYPE_CMP_NUL(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_VOID, V) #define mSCRIPT_TYPE_CMP_S(STRUCT) mSCRIPT_TYPE_MS_S(STRUCT)->name == _mSCRIPT_FIELD_NAME #define mSCRIPT_TYPE_CMP_CS(STRUCT) mSCRIPT_TYPE_MS_CS(STRUCT)->name == _mSCRIPT_FIELD_NAME -#define mSCRIPT_TYPE_CMP_S_METHOD(STRUCT, NAME) mSCRIPT_TYPE_MS_S_METHOD(STRUCT, NAME)->name == _mSCRIPT_FIELD_NAME -#define mSCRIPT_TYPE_CMP(TYPE0, TYPE1) mSCRIPT_TYPE_CMP_ ## TYPE0(TYPE1) -#define mSCRIPT_TYPE_CMP_WSTR(TYPE) (mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_STR, TYPE) || mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_CHARP, TYPE)) -#define mSCRIPT_TYPE_CMP_WLIST(TYPE) (mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_LIST, TYPE)) +#define mSCRIPT_TYPE_CMP_W(STRUCT) (false) _mVOID +#define mSCRIPT_TYPE_CMP_WSTR(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_WSTR, V) +#define mSCRIPT_TYPE_CMP_WLIST(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_WLIST, V) +#define mSCRIPT_TYPE_CMP_WTABLE(V) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_WTABLE, V) +#define mSCRIPT_TYPE_CMP(TYPE, V) \ + ((mSCRIPT_TYPE_CMP_ ## TYPE(V)) || ((V) && (V)->type->base == mSCRIPT_TYPE_WRAPPER && mSCRIPT_WRAPPER_CMP_ ## TYPE(V))) + +#define mSCRIPT_WRAPPER_CMP_U8(V) (false) +#define mSCRIPT_WRAPPER_CMP_S8(V) (false) +#define mSCRIPT_WRAPPER_CMP_U16(V) (false) +#define mSCRIPT_WRAPPER_CMP_S16(V) (false) +#define mSCRIPT_WRAPPER_CMP_U32(V) (false) +#define mSCRIPT_WRAPPER_CMP_S32(V) (false) +#define mSCRIPT_WRAPPER_CMP_F32(V) (false) +#define mSCRIPT_WRAPPER_CMP_U64(V) (false) +#define mSCRIPT_WRAPPER_CMP_S64(V) (false) +#define mSCRIPT_WRAPPER_CMP_F64(V) (false) +#define mSCRIPT_WRAPPER_CMP_BOOL(V) (false) +#define mSCRIPT_WRAPPER_CMP_STR(V) (false) +#define mSCRIPT_WRAPPER_CMP_CHARP(V) (false) +#define mSCRIPT_WRAPPER_CMP_LIST(V) (false) +#define mSCRIPT_WRAPPER_CMP_TABLE(V) (false) +#define mSCRIPT_WRAPPER_CMP_PTR(V) (false) +#define mSCRIPT_WRAPPER_CMP_WRAPPER(V) (false) +#define mSCRIPT_WRAPPER_CMP_NUL(V) (false) +#define mSCRIPT_WRAPPER_CMP_S(STRUCT) (false) _mVOID +#define mSCRIPT_WRAPPER_CMP_CS(STRUCT) (false) _mVOID +#define mSCRIPT_WRAPPER_CMP_W(STRUCT) mSCRIPT_TYPE_MS_S(STRUCT)->name == _mSCRIPT_WRAPPED_FIELD_NAME +#define mSCRIPT_WRAPPER_CMP_WSTR(V) (false) +#define mSCRIPT_WRAPPER_CMP_WLIST(V) (false) +#define mSCRIPT_WRAPPER_CMP_WTABLE(V) (false) enum mScriptTypeBase { mSCRIPT_TYPE_VOID = 0, @@ -158,7 +191,8 @@ enum mScriptClassInitType { }; enum { - mSCRIPT_VALUE_FLAG_FREE_BUFFER = 1 + mSCRIPT_VALUE_FLAG_FREE_BUFFER = 1, + mSCRIPT_VALUE_FLAG_DEINIT = 2, }; struct mScriptType; @@ -182,6 +216,7 @@ extern const struct mScriptType mSTWrapper; extern const struct mScriptType mSTWeakref; extern const struct mScriptType mSTStringWrapper; extern const struct mScriptType mSTListWrapper; +extern const struct mScriptType mSTTableWrapper; extern struct mScriptValue mScriptValueNull; @@ -202,6 +237,7 @@ struct mScriptValue { struct mScriptString* string; struct Table* table; struct mScriptList* list; + struct mScriptValue* wrapped; } value; }; @@ -224,6 +260,7 @@ struct mScriptClassMember { const char* docstring; const struct mScriptType* type; size_t offset; + bool readonly; }; struct mScriptClassCastMember { @@ -249,10 +286,10 @@ struct mScriptTypeClass { bool internal; struct Table instanceMembers; struct Table castToMembers; + struct Table setters; struct mScriptClassMember* alloc; // TODO struct mScriptClassMember* free; struct mScriptClassMember* get; - struct mScriptClassMember* set; // TODO }; struct mScriptType { @@ -303,6 +340,8 @@ void mScriptValueWrap(struct mScriptValue* val, struct mScriptValue* out); struct mScriptValue* mScriptValueUnwrap(struct mScriptValue* val); const struct mScriptValue* mScriptValueUnwrapConst(const struct mScriptValue* val); +void mScriptValueFollowPointer(struct mScriptValue* ptr, struct mScriptValue* out); + struct mScriptValue* mScriptStringCreateEmpty(size_t size); struct mScriptValue* mScriptStringCreateFromBytes(const void* string, size_t size); struct mScriptValue* mScriptStringCreateFromUTF8(const char* string); @@ -324,6 +363,8 @@ bool mScriptTableIteratorLookup(struct mScriptValue* table, struct TableIterator void mScriptFrameInit(struct mScriptFrame* frame); void mScriptFrameDeinit(struct mScriptFrame* frame); +struct mScriptValue* mScriptLambdaCreate0(struct mScriptValue* fn, struct mScriptList* args); + void mScriptClassInit(struct mScriptTypeClass* cls); void mScriptClassDeinit(struct mScriptTypeClass* cls); @@ -332,6 +373,7 @@ bool mScriptObjectGetConst(const struct mScriptValue* obj, const char* member, s bool mScriptObjectSet(struct mScriptValue* obj, const char* member, struct mScriptValue*); bool mScriptObjectCast(const struct mScriptValue* input, const struct mScriptType* type, struct mScriptValue* output) ; void mScriptObjectFree(struct mScriptValue* obj); +struct mScriptValue* mScriptObjectBindLambda(struct mScriptValue* obj, const char* member, struct mScriptList* args); bool mScriptPopS32(struct mScriptList* list, int32_t* out); bool mScriptPopU32(struct mScriptList* list, uint32_t* out); diff --git a/res/entitlements.plist b/res/entitlements.plist new file mode 100644 index 000000000..33cd79505 --- /dev/null +++ b/res/entitlements.plist @@ -0,0 +1,7 @@ + + + + com.apple.security.device.camera + + + diff --git a/res/font-mask.png b/res/font-mask.png new file mode 100644 index 000000000..2e223597b Binary files /dev/null and b/res/font-mask.png differ diff --git a/res/font-sdf.png b/res/font-sdf.png new file mode 100644 index 000000000..95960e26c Binary files /dev/null and b/res/font-sdf.png differ diff --git a/res/info.plist.in b/res/info.plist.in index eb625299c..f4b9bba80 100644 --- a/res/info.plist.in +++ b/res/info.plist.in @@ -32,6 +32,8 @@ ${MACOSX_BUNDLE_COPYRIGHT} NSSupportsAutomaticGraphicsSwitching + NSCameraUsageDescription + Only used when Game Boy Camera is selected and a physical camera is set CFBundleDocumentTypes diff --git a/res/nointro.dat b/res/nointro.dat index ac844f883..d63e3f818 100644 --- a/res/nointro.dat +++ b/res/nointro.dat @@ -1,8 +1,8 @@ clrmamepro ( name "Nintendo - Game Boy Advance" description "Nintendo - Game Boy Advance" - version 20220828-205130 - author "aci68, Arctic Circle System, Aringon, Bent, BigFred, bikerspade, C. V. Reynolds, chillerecke, DeadSkullzJr, Densetsu, DeriLoko3, einstein95, ElBarto, Enker, Flashfire42, fuzzball, Gefflon, Hiccup, hking0036, hydr0x, InternalLoss, Jack, jimmsu, kazumi213, Larsenv, Lesserkuma, Madeline, MeguCocoa, Money_114, NESBrew12, niemand, nnssxx, norkmetnoil577, omonim2007, Powerpuff, PPLToast, relax, RetroGamer, Rifu, sCZther, SonGoku, Tauwasser, togemet2, ufocrossing, Vallaine01, Whovian9369, xuom2, zg" + version 20240104-012251 + author "aci68, Arctic Circle System, Aringon, Bent, BigFred, bikerspade, C. V. Reynolds, chillerecke, DeadSkullzJr, Densetsu, DeriLoko3, einstein95, ElBarto, Enker, FakeShemp, Flashfire42, fuzzball, Gefflon, Hiccup, hking0036, hydr0x, InternalLoss, Jack, jimmsu, Just001Kim, kazumi213, Larsenv, Lesserkuma, Madeline, MeguCocoa, Money_114, NESBrew12, niemand, nnssxx, norkmetnoil577, NovaAurora, omonim2007, Powerpuff, PPLToast, Prominos, Psychofox11, psykopat, rarenight, relax, RetroGamer, Rifu, sCZther, SonGoku, Tauwasser, Tescu, togemet2, ufocrossing, Vallaine01, Whovian9369, xprism, xuom2, zg" homepage No-Intro url "https://www.no-intro.org" forcenodump required @@ -19,9 +19,9 @@ game ( ) game ( - name "[BIOS] Game Boy Advance (Japan) (Debug Version)" - description "[BIOS] Game Boy Advance (Japan) (Debug Version)" - rom ( name "[BIOS] Game Boy Advance (Japan) (Debug Version).bin" size 16384 crc 15e1f676 sha1 aa98a2ad32b86106340665d1222d7d973a1361c7 ) + name "[BIOS] Game Boy Advance (World) (Beta)" + description "[BIOS] Game Boy Advance (World) (Beta)" + rom ( name "[BIOS] Game Boy Advance (World) (Beta).bin" size 16384 crc 15e1f676 sha1 aa98a2ad32b86106340665d1222d7d973a1361c7 ) ) game ( @@ -30,6 +30,12 @@ game ( rom ( name "[BIOS] Game Boy Advance (World).bin" size 16384 crc 81977335 sha1 300c20df6731a33952ded8c436f7f186d25d3492 flags verified ) ) +game ( + name "[BIOS] Game Boy Advance (GBC Mode) (World)" + description "[BIOS] Game Boy Advance (GBC Mode) (World)" + rom ( name "[BIOS] Game Boy Advance (GBC Mode) (World).gbc" size 2304 crc ffd6b0f1 sha1 fa5287e24b0fa533b3b5ef2b28a81245346c1a0f ) +) + game ( name "007 - Everything or Nothing (USA, Europe) (En,Fr,De)" description "007 - Everything or Nothing (USA, Europe) (En,Fr,De)" @@ -45,7 +51,7 @@ game ( game ( name "007 - NightFire (USA, Europe) (En,Fr,De)" description "007 - NightFire (USA, Europe) (En,Fr,De)" - rom ( name "007 - NightFire (USA, Europe) (En,Fr,De).gba" size 8388608 crc 56c83c16 sha1 f4363923181b71448ddd6e28ac72d30b3ecfc019 ) + rom ( name "007 - NightFire (USA, Europe) (En,Fr,De).gba" size 8388608 crc 56c83c16 sha1 f4363923181b71448ddd6e28ac72d30b3ecfc019 flags verified ) ) game ( @@ -423,7 +429,7 @@ game ( game ( name "2 Games in 1 - Sonic Battle + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It)" description "2 Games in 1 - Sonic Battle + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It)" - rom ( name "2 Games in 1 - Sonic Battle + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It).gba" size 33554432 crc a50de233 sha1 df086e816109a18d0f037e8c0aa7a2ae40677c14 ) + rom ( name "2 Games in 1 - Sonic Battle + Sonic Pinball Party (Europe) (En,Ja,Fr,De,Es,It).gba" size 33554432 crc a50de233 sha1 df086e816109a18d0f037e8c0aa7a2ae40677c14 flags verified ) ) game ( @@ -483,7 +489,7 @@ game ( game ( name "2 Games in 1 - The SpongeBob SquarePants Movie + SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,Nl)" description "2 Games in 1 - The SpongeBob SquarePants Movie + SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,Nl)" - rom ( name "2 Games in 1 - The SpongeBob SquarePants Movie + SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,Nl).gba" size 16777216 crc a04cebfe sha1 0286e31772601f7c7420722e8fbf8a210d562a06 ) + rom ( name "2 Games in 1 - The SpongeBob SquarePants Movie + SpongeBob SquarePants and Friends in Freeze Frame Frenzy (Europe) (En,Fr,De,Es,It,Nl+En,Fr,De,Es,Nl).gba" size 16777216 crc a04cebfe sha1 0286e31772601f7c7420722e8fbf8a210d562a06 flags verified ) ) game ( @@ -561,7 +567,7 @@ game ( game ( name "2 in 1 - V-Rally 3 + Stuntman (Europe) (En,Fr,De,Es,It)" description "2 in 1 - V-Rally 3 + Stuntman (Europe) (En,Fr,De,Es,It)" - rom ( name "2 in 1 - V-Rally 3 + Stuntman (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5813810f sha1 f116cc8e6a7f6dba49564031a2ac63d837d4f11b ) + rom ( name "2 in 1 - V-Rally 3 + Stuntman (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5813810f sha1 f116cc8e6a7f6dba49564031a2ac63d837d4f11b flags verified ) ) game ( @@ -585,7 +591,7 @@ game ( game ( name "2 in 1 Game Pack - Spider-Man & Spider-Man 2 (Europe) (En,Fr,De+En,Fr,De,Es,It)" description "2 in 1 Game Pack - Spider-Man & Spider-Man 2 (Europe) (En,Fr,De+En,Fr,De,Es,It)" - rom ( name "2 in 1 Game Pack - Spider-Man & Spider-Man 2 (Europe) (En,Fr,De+En,Fr,De,Es,It).gba" size 33554432 crc d732e52d sha1 5bf33c1f0fd50f268ed5941d3246cfad1893ef89 ) + rom ( name "2 in 1 Game Pack - Spider-Man & Spider-Man 2 (Europe) (En,Fr,De+En,Fr,De,Es,It).gba" size 33554432 crc e76db6ef sha1 287071f81572a95cf3a3b35fab93862733864c3e ) ) game ( @@ -630,6 +636,12 @@ game ( rom ( name "2-in-1 Fun Pack - Shrek 2 + Madagascar - Operation Penguin (Europe).gba" size 16777216 crc 3535b2bf sha1 be51cfa607d461efd1dab640a5b4f5b037c060df ) ) +game ( + name "2004Mbit Competition (World) (Unl)" + description "2004Mbit Competition (World) (Unl)" + rom ( name "2004Mbit Competition (World) (Unl).gba" size 4194304 crc 107de6b7 sha1 0cf3dec1b8ff2372e4fbe339c0b338d590b39256 ) +) + game ( name "2006 FIFA World Cup - Germany 2006 (USA, Europe) (En,Fr,De,Es,It)" description "2006 FIFA World Cup - Germany 2006 (USA, Europe) (En,Fr,De,Es,It)" @@ -637,9 +649,9 @@ game ( ) game ( - name "2K Sports - Major League Baseball 2K7 (USA)" - description "2K Sports - Major League Baseball 2K7 (USA)" - rom ( name "2K Sports - Major League Baseball 2K7 (USA).gba" size 8388608 crc 8f3ff0e4 sha1 07390bc2bd53cd9ee5c6d2805ad374c59c195d9f ) + name "2048 Pool (World) (Aftermarket) (Unl)" + description "2048 Pool (World) (Aftermarket) (Unl)" + rom ( name "2048 Pool (World) (Aftermarket) (Unl).gba" size 203440 crc 9df6ae4f sha1 c93a9cf3502237b474e70de8dee274901ee7ecb2 ) ) game ( @@ -648,10 +660,16 @@ game ( rom ( name "2K Sports - Major League Baseball 2K7 (USA) (Beta).gba" size 8388608 crc ea51532d sha1 776e084ac31336114f23230bde4adfc1f231934b ) ) +game ( + name "2K Sports - Major League Baseball 2K7 (USA)" + description "2K Sports - Major League Baseball 2K7 (USA)" + rom ( name "2K Sports - Major League Baseball 2K7 (USA).gba" size 8388608 crc 8f3ff0e4 sha1 07390bc2bd53cd9ee5c6d2805ad374c59c195d9f ) +) + game ( name "3 Game Pack! - Candy Land + Chutes and Ladders + Original Memory Game (USA)" description "3 Game Pack! - Candy Land + Chutes and Ladders + Original Memory Game (USA)" - rom ( name "3 Game Pack! - Candy Land + Chutes and Ladders + Original Memory Game (USA).gba" size 4194304 crc 628a8e32 sha1 946ccbf8d21adc7a5587ef85a9759a2ded23875d ) + rom ( name "3 Game Pack! - Candy Land + Chutes and Ladders + Original Memory Game (USA).gba" size 4194304 crc 628a8e32 sha1 946ccbf8d21adc7a5587ef85a9759a2ded23875d flags verified ) ) game ( @@ -741,7 +759,7 @@ game ( game ( name "4 Games on One Game Pak (Racing) (USA) (En,Fr,De,Es,It)" description "4 Games on One Game Pak (Racing) (USA) (En,Fr,De,Es,It)" - rom ( name "4 Games on One Game Pak (Racing) (USA) (En,Fr,De,Es,It).gba" size 33554432 crc 04a40017 sha1 a99bbc7ec018af85260669917939004baabf4ac1 ) + rom ( name "4 Games on One Game Pak (Racing) (USA) (En,Fr,De,Es,It).gba" size 33554432 crc 04a40017 sha1 a99bbc7ec018af85260669917939004baabf4ac1 flags verified ) ) game ( @@ -757,15 +775,15 @@ game ( ) game ( - name "Ace Combat Advance (Europe) (En,Fr,De,Es,It) (Beta)" - description "Ace Combat Advance (Europe) (En,Fr,De,Es,It) (Beta)" - rom ( name "Ace Combat Advance (Europe) (En,Fr,De,Es,It) (Beta).gba" size 4194304 crc 76da5c78 sha1 6e5c57049866596db0e977b80e499b868e0394c2 ) + name "Ace Combat Advance (USA, Europe)" + description "Ace Combat Advance (USA, Europe)" + rom ( name "Ace Combat Advance (USA, Europe).gba" size 4194304 crc 43f5e157 sha1 856a08e8f60f817b96add5bf2f6db186bea832ef flags verified ) ) game ( - name "Ace Combat Advance (USA, Europe)" - description "Ace Combat Advance (USA, Europe)" - rom ( name "Ace Combat Advance (USA, Europe).gba" size 4194304 crc 43f5e157 sha1 856a08e8f60f817b96add5bf2f6db186bea832ef ) + name "Ace Combat Advance (Europe) (En,Fr,De,Es,It) (Beta)" + description "Ace Combat Advance (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Ace Combat Advance (Europe) (En,Fr,De,Es,It) (Beta).gba" size 4194304 crc 76da5c78 sha1 6e5c57049866596db0e977b80e499b868e0394c2 ) ) game ( @@ -843,7 +861,7 @@ game ( game ( name "Activision Anthology (USA)" description "Activision Anthology (USA)" - rom ( name "Activision Anthology (USA).gba" size 8388608 crc 14a28d68 sha1 5125bbbbf1df7782590d99273735826636a2f9ba ) + rom ( name "Activision Anthology (USA).gba" size 8388608 crc 14a28d68 sha1 5125bbbbf1df7782590d99273735826636a2f9ba flags verified ) ) game ( @@ -903,7 +921,7 @@ game ( game ( name "Advance Wars (USA) (Rev 1)" description "Advance Wars (USA) (Rev 1)" - rom ( name "Advance Wars (USA) (Rev 1).gba" size 4194304 crc 26fd0fc9 sha1 15053499d5b3f49128a941d7f2d84876f5424d0c ) + rom ( name "Advance Wars (USA) (Rev 1).gba" size 4194304 crc 26fd0fc9 sha1 15053499d5b3f49128a941d7f2d84876f5424d0c flags verified ) ) game ( @@ -985,27 +1003,33 @@ game ( ) game ( - name "Aero the Acro-Bat (USA) (Beta)" - description "Aero the Acro-Bat (USA) (Beta)" - rom ( name "Aero the Acro-Bat (USA) (Beta).gba" size 1030244 crc beed50f0 sha1 68c0a00275c7135ca1a116ccced1ecede75819b8 ) + name "Adventures of Mr. Bean (Europe) (Demo)" + description "Adventures of Mr. Bean (Europe) (Demo)" + rom ( name "Adventures of Mr. Bean (Europe) (Demo).gba" size 2097152 crc 5e3b686d sha1 158856b0b438217ddf8b900ba9c5dca3d6457c7f ) ) game ( - name "Aero the Acro-Bat - Rascal Rival Revenge (Europe)" - description "Aero the Acro-Bat - Rascal Rival Revenge (Europe)" - rom ( name "Aero the Acro-Bat - Rascal Rival Revenge (Europe).gba" size 4194304 crc a7e98ebe sha1 11050975c211550a8bea751212ceb8856daea759 flags verified ) + name "Aero the Acro-Bat (USA) (Beta 1)" + description "Aero the Acro-Bat (USA) (Beta 1)" + rom ( name "Aero the Acro-Bat (USA) (Beta 1).gba" size 1030244 crc beed50f0 sha1 68c0a00275c7135ca1a116ccced1ecede75819b8 ) ) game ( - name "Aero the Acro-Bat - Rascal Rival Revenge (Europe) (Beta)" - description "Aero the Acro-Bat - Rascal Rival Revenge (Europe) (Beta)" - rom ( name "Aero the Acro-Bat - Rascal Rival Revenge (Europe) (Beta).gba" size 4194304 crc 6f3ea564 sha1 3f88084c501fb15820f6ad9a9c87ac21af3b59eb ) + name "Aero the Acro-Bat (Europe)" + description "Aero the Acro-Bat (Europe)" + rom ( name "Aero the Acro-Bat (Europe).gba" size 4194304 crc a7e98ebe sha1 11050975c211550a8bea751212ceb8856daea759 flags verified ) ) game ( - name "Aero the Acro-Bat - Rascal Rival Revenge (USA)" - description "Aero the Acro-Bat - Rascal Rival Revenge (USA)" - rom ( name "Aero the Acro-Bat - Rascal Rival Revenge (USA).gba" size 4194304 crc b47ac020 sha1 cdbc609df128127d05c435f59b781958c0e751fd ) + name "Aero the Acro-Bat (USA)" + description "Aero the Acro-Bat (USA)" + rom ( name "Aero the Acro-Bat (USA).gba" size 4194304 crc b47ac020 sha1 cdbc609df128127d05c435f59b781958c0e751fd ) +) + +game ( + name "Aero the Acro-Bat - Rascal Rival Revenge (USA) (Beta 2) (2002-03-27)" + description "Aero the Acro-Bat - Rascal Rival Revenge (USA) (Beta 2) (2002-03-27)" + rom ( name "Aero the Acro-Bat - Rascal Rival Revenge (USA) (Beta 2) (2002-03-27).gba" size 4194304 crc 6f3ea564 sha1 3f88084c501fb15820f6ad9a9c87ac21af3b59eb ) ) game ( @@ -1020,6 +1044,12 @@ game ( rom ( name "Agassi Tennis Generation (USA).gba" size 4194304 crc 8ba179b8 sha1 1797251886d165e136ce6ba564ad8c8ec865d829 ) ) +game ( + name "AGB Aging Cartridge (World) (v1.0) (Test Program)" + description "AGB Aging Cartridge (World) (v1.0) (Test Program)" + rom ( name "AGB Aging Cartridge (World) (v1.0) (Test Program).gba" size 4194304 crc d2e80e33 sha1 30b3ea4b0c2611a7d8aaf1cacbe8c3b79eb2ab78 ) +) + game ( name "AGB-Parallel Interface Cartridge (Japan) (En) (Program)" description "AGB-Parallel Interface Cartridge (Japan) (En) (Program)" @@ -1045,9 +1075,9 @@ game ( ) game ( - name "AGS Aging Cartridge (World) (v7.0) (Test Program)" - description "AGS Aging Cartridge (World) (v7.0) (Test Program)" - rom ( name "AGS Aging Cartridge (World) (v7.0) (Test Program).gba" size 2097152 crc bbb6a960 sha1 c67e0a5e26ea5eba2bc11c99d003027a96e44060 flags verified ) + name "Agoria - Ode to Fate (World) (Aftermarket) (Unl)" + description "Agoria - Ode to Fate (World) (Aftermarket) (Unl)" + rom ( name "Agoria - Ode to Fate (World) (Aftermarket) (Unl).gba" size 2725504 crc 67d3361f sha1 cb0b83b85a290c223cd3249b37ae7207d3efde06 ) ) game ( @@ -1063,9 +1093,15 @@ game ( ) game ( - name "AGS Aging Cartridge (World) (v9.0) (Test Program)" - description "AGS Aging Cartridge (World) (v9.0) (Test Program)" - rom ( name "AGS Aging Cartridge (World) (v9.0) (Test Program).gba" size 2097152 crc 2e69686d sha1 03d3a486482b61128872519fd755d0c072c12d93 ) + name "AGS Aging Cartridge (World) (Rev 3) (v9.0) (Test Program)" + description "AGS Aging Cartridge (World) (Rev 3) (v9.0) (Test Program)" + rom ( name "AGS Aging Cartridge (World) (Rev 3) (v9.0) (Test Program).gba" size 4194304 crc 584bbdc7 sha1 4a21b60c23014750250e56a8a22b886032f0d33d ) +) + +game ( + name "AGS Aging Cartridge (World) (Rev 1) (v7.0) (Test Program)" + description "AGS Aging Cartridge (World) (Rev 1) (v7.0) (Test Program)" + rom ( name "AGS Aging Cartridge (World) (Rev 1) (v7.0) (Test Program).gba" size 4194304 crc e16e1360 sha1 5c73fb4074b19c5a1a9bb60fd359b528d2ed99a6 ) ) game ( @@ -1083,13 +1119,7 @@ game ( game ( name "AirForce Delta Storm (USA) (En,Ja,Fr,De)" description "AirForce Delta Storm (USA) (En,Ja,Fr,De)" - rom ( name "AirForce Delta Storm (USA) (En,Ja,Fr,De).gba" size 4194304 crc ebf757b8 sha1 7bc53480a43ada2aad32d798ab00b6e761726728 ) -) - -game ( - name "Aka-chan Doubutsuen (Japan) (Rev 1)" - description "Aka-chan Doubutsuen (Japan) (Rev 1)" - rom ( name "Aka-chan Doubutsuen (Japan) (Rev 1).gba" size 4194304 crc c1072e26 sha1 634624c77c90a8ff40bec9046133c50041efc49b ) + rom ( name "AirForce Delta Storm (USA) (En,Ja,Fr,De).gba" size 4194304 crc ebf757b8 sha1 7bc53480a43ada2aad32d798ab00b6e761726728 flags verified ) ) game ( @@ -1098,6 +1128,12 @@ game ( rom ( name "Aka-chan Doubutsuen (Japan).gba" size 4194304 crc b50cd166 sha1 9a0623a8680c4cf9b745f940b99da0a192764828 ) ) +game ( + name "Aka-chan Doubutsuen (Japan) (Rev 1)" + description "Aka-chan Doubutsuen (Japan) (Rev 1)" + rom ( name "Aka-chan Doubutsuen (Japan) (Rev 1).gba" size 4194304 crc c1072e26 sha1 634624c77c90a8ff40bec9046133c50041efc49b ) +) + game ( name "Akumajou Dracula - Circle of the Moon (Japan) (Virtual Console)" description "Akumajou Dracula - Circle of the Moon (Japan) (Virtual Console)" @@ -1146,12 +1182,6 @@ game ( rom ( name "Aleck Bordon Adventure - Tower & Shaft Advance (Japan).gba" size 4194304 crc e068728f sha1 2def9d7ea29a0ed5845b354e433e0a55e979f636 ) ) -game ( - name "Alex Ferguson's Player Manager 2002 ~ Total Soccer Manager (Europe) (En,Fr,De,Es,It,Nl)" - description "Alex Ferguson's Player Manager 2002 ~ Total Soccer Manager (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Alex Ferguson's Player Manager 2002 ~ Total Soccer Manager (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 92f99295 sha1 a870e1321a8ad3317cd695fcc0c713441c25919f ) -) - game ( name "Alex Rider - Stormbreaker (USA)" description "Alex Rider - Stormbreaker (USA)" @@ -1173,7 +1203,7 @@ game ( game ( name "Alienators - Evolution Continues (USA, Europe)" description "Alienators - Evolution Continues (USA, Europe)" - rom ( name "Alienators - Evolution Continues (USA, Europe).gba" size 4194304 crc 0d694ca4 sha1 fb691c5e21fa388d75497e9090db82dec881e422 ) + rom ( name "Alienators - Evolution Continues (USA, Europe).gba" size 4194304 crc 0d694ca4 sha1 fb691c5e21fa388d75497e9090db82dec881e422 flags verified ) ) game ( @@ -1209,7 +1239,7 @@ game ( game ( name "Altered Beast - Guardian of the Realms (USA)" description "Altered Beast - Guardian of the Realms (USA)" - rom ( name "Altered Beast - Guardian of the Realms (USA).gba" size 8388608 crc c4955f69 sha1 194dc1fff5578dcd8a2a6914647f1b67334f2a8a ) + rom ( name "Altered Beast - Guardian of the Realms (USA).gba" size 8388608 crc c4955f69 sha1 194dc1fff5578dcd8a2a6914647f1b67334f2a8a flags verified ) ) game ( @@ -1273,9 +1303,69 @@ game ( ) game ( - name "Anguna - Warriors of Virtue (World) (Aftermarket) (Homebrew)" - description "Anguna - Warriors of Virtue (World) (Aftermarket) (Homebrew)" - rom ( name "Anguna - Warriors of Virtue (World) (Aftermarket) (Homebrew).gba" size 1710888 crc 3346891f sha1 270c426705df767a4ad2dc69d039842442f779b2 ) + name "Anguna - Warriors of Virtue (World) (v0.95) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v0.95) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.95) (Aftermarket) (Unl).gba" size 1710888 crc 3346891f sha1 270c426705df767a4ad2dc69d039842442f779b2 flags verified ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (2021-02-28) (Patreon) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (2021-02-28) (Patreon) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (2021-02-28) (Patreon) (Aftermarket) (Unl).gba" size 1729120 crc a354d555 sha1 d7cd0ab9d622187d4ce55bf0c7f14a24ee781710 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v0.95) (Itch.io) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v0.95) (Itch.io) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.95) (Itch.io) (Aftermarket) (Unl).gba" size 1775856 crc 41ea5b0b sha1 e351bc6a9046ec002fc2dfdee061047908bd4350 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (Retro-Bit Generations) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (Retro-Bit Generations) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (Retro-Bit Generations) (Aftermarket) (Unl).gba" size 1775660 crc a234813c sha1 ad904624bf198a164ba580eea326cd30fffebac8 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (Demo) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (Demo) (Aftermarket) (Unl).gba" size 597104 crc 0a9098b4 sha1 0992fb6f38e49426adc834fb3831748a1caa1bc0 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v2.0) (Demo) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v2.0) (Demo) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v2.0) (Demo) (Aftermarket) (Unl).gba" size 811840 crc 63c1cc2c sha1 faca8225ee20b8e5edb14e005af77b63c6f51446 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v0.91) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v0.91) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.91) (Aftermarket) (Unl).gba" size 1714000 crc eebb016f sha1 008a9d06f78bccc540ca4ece4d1982de76f95901 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v0.92) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v0.92) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.92) (Aftermarket) (Unl).gba" size 1710624 crc ba271987 sha1 04f1e79e79e894d8f45ed1ea2ff5aa67053f0ab3 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v0.93) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v0.93) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.93) (Aftermarket) (Unl).gba" size 1710624 crc df7108e3 sha1 bd267fd7e762acb8cd595e54bfd51a139864759e ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v0.93) (Aftermarket) (Unl) (Alt)" + description "Anguna - Warriors of Virtue (World) (v0.93) (Aftermarket) (Unl) (Alt)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.93) (Aftermarket) (Unl) (Alt).gba" size 1714000 crc 54ff2e56 sha1 0386315fc140db2a43a6f927c04de658bd800da9 ) +) + +game ( + name "Anguna - Warriors of Virtue (World) (v0.94) (Aftermarket) (Unl)" + description "Anguna - Warriors of Virtue (World) (v0.94) (Aftermarket) (Unl)" + rom ( name "Anguna - Warriors of Virtue (World) (v0.94) (Aftermarket) (Unl).gba" size 1710952 crc cb4e2768 sha1 a7297cf4ecffc1f93f86edde68e1ff42e8099f3b ) ) game ( @@ -1293,7 +1383,7 @@ game ( game ( name "Animal Snap - Rescue Them 2 by 2 (USA)" description "Animal Snap - Rescue Them 2 by 2 (USA)" - rom ( name "Animal Snap - Rescue Them 2 by 2 (USA).gba" size 4194304 crc 7304dca4 sha1 899b9158f622ab145c6787b2af65abda902e6a95 ) + rom ( name "Animal Snap - Rescue Them 2 by 2 (USA).gba" size 4194304 crc 7304dca4 sha1 899b9158f622ab145c6787b2af65abda902e6a95 flags verified ) ) game ( @@ -1315,9 +1405,15 @@ game ( ) game ( - name "Another World (World) (En,Fr) (Unl)" - description "Another World (World) (En,Fr) (Unl)" - rom ( name "Another World (World) (En,Fr) (Unl).gba" size 2010358 crc 86c4f772 sha1 41d39a0c34f72469dd3fbcc90190605b8ada93e6 ) + name "Another World (Europe) (En,Fr) (v2.1) (Unl)" + description "Another World (Europe) (En,Fr) (v2.1) (Unl)" + rom ( name "Another World (Europe) (En,Fr) (v2.1) (Unl).gba" size 2010358 crc 86c4f772 sha1 41d39a0c34f72469dd3fbcc90190605b8ada93e6 ) +) + +game ( + name "Another World (Europe) (Fr) (v1.2) (Unl)" + description "Another World (Europe) (Fr) (v1.2) (Unl)" + rom ( name "Another World (Europe) (Fr) (v1.2) (Unl).gba" size 1823864 crc 1a1397de sha1 5bcc5c9a633e2226411dd41f1a191b9fcc793d92 ) ) game ( @@ -1332,24 +1428,30 @@ game ( rom ( name "Ant Bully, The (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 52dc386b sha1 a735364887c31a19fa7d250ec830d02220d6a6cd ) ) -game ( - name "Antz - Extreme Racing (USA)" - description "Antz - Extreme Racing (USA)" - rom ( name "Antz - Extreme Racing (USA).gba" size 4194304 crc f4efc5ed sha1 ad6ded0f643457d652292bb97e30b1ad442e41da ) -) - game ( name "Antz - Extreme Racing (Europe) (En,Fr,De,Es,It,Nl)" description "Antz - Extreme Racing (Europe) (En,Fr,De,Es,It,Nl)" rom ( name "Antz - Extreme Racing (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 367927ed sha1 68fca49cba74dc108f50ec762ab91b6dff5a92b8 ) ) +game ( + name "Antz - Extreme Racing (USA)" + description "Antz - Extreme Racing (USA)" + rom ( name "Antz - Extreme Racing (USA).gba" size 4194304 crc f4efc5ed sha1 ad6ded0f643457d652292bb97e30b1ad442e41da ) +) + game ( name "Ao-Zora to Nakama-tachi - Yume no Bouken (Japan)" description "Ao-Zora to Nakama-tachi - Yume no Bouken (Japan)" rom ( name "Ao-Zora to Nakama-tachi - Yume no Bouken (Japan).gba" size 4194304 crc ad9af125 sha1 0e6c92477793ce495caa400899effb4f87384f3c ) ) +game ( + name "Apotris (World) (v3.4.5) (Aftermarket) (Unl)" + description "Apotris (World) (v3.4.5) (Aftermarket) (Unl)" + rom ( name "Apotris (World) (v3.4.5) (Aftermarket) (Unl).gba" size 4194304 crc 55ae4312 sha1 fb7142bcc30f71f187cc51b7fcbc5a3958374c6c ) +) + game ( name "Archer Maclean's 3D Pool (USA)" description "Archer Maclean's 3D Pool (USA)" @@ -1365,25 +1467,25 @@ game ( game ( name "Army Men - Operation Green (USA) (En,Fr,De,Es,It)" description "Army Men - Operation Green (USA) (En,Fr,De,Es,It)" - rom ( name "Army Men - Operation Green (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 6d174e28 sha1 b0fa4769cddbc66bc333ad45658524a4aeeec755 ) + rom ( name "Army Men - Operation Green (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 6d174e28 sha1 b0fa4769cddbc66bc333ad45658524a4aeeec755 flags verified ) ) game ( name "Army Men - Turf Wars (USA)" description "Army Men - Turf Wars (USA)" - rom ( name "Army Men - Turf Wars (USA).gba" size 8388608 crc 65ac74cc sha1 43bfc86185a06d9d9c27686ad8cb650288b716ae ) + rom ( name "Army Men - Turf Wars (USA).gba" size 8388608 crc 65ac74cc sha1 43bfc86185a06d9d9c27686ad8cb650288b716ae flags verified ) ) game ( name "Army Men Advance (USA, Europe) (En,Fr,De,Es,It)" description "Army Men Advance (USA, Europe) (En,Fr,De,Es,It)" - rom ( name "Army Men Advance (USA, Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 9a4a509f sha1 43cd22c8e5832790b0cdbdcf0e11859021747342 ) + rom ( name "Army Men Advance (USA, Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 9a4a509f sha1 43cd22c8e5832790b0cdbdcf0e11859021747342 flags verified ) ) game ( name "Around the World in 80 Days (USA)" description "Around the World in 80 Days (USA)" - rom ( name "Around the World in 80 Days (USA).gba" size 4194304 crc c2c22af2 sha1 a3649682ef8a2378767154b37ca854d615305646 ) + rom ( name "Around the World in 80 Days (USA).gba" size 4194304 crc c2c22af2 sha1 a3649682ef8a2378767154b37ca854d615305646 flags verified ) ) game ( @@ -1395,7 +1497,7 @@ game ( game ( name "Arthur and the Invisibles (USA) (En,Fr,Es)" description "Arthur and the Invisibles (USA) (En,Fr,Es)" - rom ( name "Arthur and the Invisibles (USA) (En,Fr,Es).gba" size 16777216 crc 87c25055 sha1 6173ea7e00497e7a908a97e64cb4bc86396e8459 ) + rom ( name "Arthur and the Invisibles (USA) (En,Fr,Es).gba" size 16777216 crc 87c25055 sha1 6173ea7e00497e7a908a97e64cb4bc86396e8459 flags verified ) ) game ( @@ -1443,13 +1545,13 @@ game ( game ( name "Astro Boy - Omega Factor (Europe) (En,Ja,Fr,De,Es,It)" description "Astro Boy - Omega Factor (Europe) (En,Ja,Fr,De,Es,It)" - rom ( name "Astro Boy - Omega Factor (Europe) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 1e2e8937 sha1 9a4fc3533bbdb28fd5945bd1ee7d84d992eee12f ) + rom ( name "Astro Boy - Omega Factor (Europe) (En,Ja,Fr,De,Es,It).gba" size 8388608 crc 1e2e8937 sha1 9a4fc3533bbdb28fd5945bd1ee7d84d992eee12f flags verified ) ) game ( name "Astro Boy - Tetsuwan Atom - Atom Heart no Himitsu (Japan)" description "Astro Boy - Tetsuwan Atom - Atom Heart no Himitsu (Japan)" - rom ( name "Astro Boy - Tetsuwan Atom - Atom Heart no Himitsu (Japan).gba" size 8388608 crc e2d94b0d sha1 ca16dc4044b9ae98a26c826bb3cc19a7e8315315 ) + rom ( name "Astro Boy - Tetsuwan Atom - Atom Heart no Himitsu (Japan).gba" size 8388608 crc e2d94b0d sha1 ca16dc4044b9ae98a26c826bb3cc19a7e8315315 flags verified ) ) game ( @@ -1476,6 +1578,12 @@ game ( rom ( name "Atlantis - The Lost Empire (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc b3948dbc sha1 93624eaa9a80cdb791bd14955b55dd7c58c4abbd ) ) +game ( + name "Atomic Betty (USA, Europe)" + description "Atomic Betty (USA, Europe)" + rom ( name "Atomic Betty (USA, Europe).gba" size 8388608 crc 8919d82c sha1 59e7400802ab634065b9674de3f437ddf8309d6e flags verified ) +) + game ( name "Atomic Betty (USA, Europe) (Beta)" description "Atomic Betty (USA, Europe) (Beta)" @@ -1483,9 +1591,9 @@ game ( ) game ( - name "Atomic Betty (USA, Europe)" - description "Atomic Betty (USA, Europe)" - rom ( name "Atomic Betty (USA, Europe).gba" size 8388608 crc 8919d82c sha1 59e7400802ab634065b9674de3f437ddf8309d6e ) + name "ATV - Quad Power Racing (USA, Europe)" + description "ATV - Quad Power Racing (USA, Europe)" + rom ( name "ATV - Quad Power Racing (USA, Europe).gba" size 4194304 crc 9c1a7dcb sha1 43a2c71b1f3b4085adee648e5a409be4517cd7bb flags verified ) ) game ( @@ -1494,12 +1602,6 @@ game ( rom ( name "ATV - Quad Power Racing (Europe) (En,Fr,De,Es,It) (Rev 1).gba" size 4194304 crc 4b4e8bc7 sha1 2234f23928c871b00bd48bdcdd5273362d4e0cdc ) ) -game ( - name "ATV - Quad Power Racing (USA, Europe)" - description "ATV - Quad Power Racing (USA, Europe)" - rom ( name "ATV - Quad Power Racing (USA, Europe).gba" size 4194304 crc 9c1a7dcb sha1 43a2c71b1f3b4085adee648e5a409be4517cd7bb ) -) - game ( name "ATV - Thunder Ridge Riders (USA)" description "ATV - Thunder Ridge Riders (USA)" @@ -1515,7 +1617,7 @@ game ( game ( name "Avatar - The Last Airbender (USA)" description "Avatar - The Last Airbender (USA)" - rom ( name "Avatar - The Last Airbender (USA).gba" size 8388608 crc 946787c0 sha1 9d864e9b3ccce4e5e1b1c566afa0d06088e88dfd ) + rom ( name "Avatar - The Last Airbender (USA).gba" size 8388608 crc 946787c0 sha1 9d864e9b3ccce4e5e1b1c566afa0d06088e88dfd flags verified ) ) game ( @@ -1575,7 +1677,7 @@ game ( game ( name "Back to Stone (USA) (En,Fr)" description "Back to Stone (USA) (En,Fr)" - rom ( name "Back to Stone (USA) (En,Fr).gba" size 4194304 crc 4c29c9c8 sha1 db1fe7581858053b58412a97df262b46838a7be7 ) + rom ( name "Back to Stone (USA) (En,Fr).gba" size 4194304 crc 4c29c9c8 sha1 db1fe7581858053b58412a97df262b46838a7be7 flags verified ) ) game ( @@ -1611,7 +1713,7 @@ game ( game ( name "Backyard Baseball (USA)" description "Backyard Baseball (USA)" - rom ( name "Backyard Baseball (USA).gba" size 4194304 crc 9f36b4e5 sha1 657a639ab3ffbfc85c7a0da51d640ac2e60ec430 ) + rom ( name "Backyard Baseball (USA).gba" size 4194304 crc 9f36b4e5 sha1 657a639ab3ffbfc85c7a0da51d640ac2e60ec430 flags verified ) ) game ( @@ -1653,7 +1755,7 @@ game ( game ( name "Backyard Sports - Baseball 2007 (USA)" description "Backyard Sports - Baseball 2007 (USA)" - rom ( name "Backyard Sports - Baseball 2007 (USA).gba" size 4194304 crc 0ee82569 sha1 cde84171b11a767338158c61ee2ad608d4eb8889 ) + rom ( name "Backyard Sports - Baseball 2007 (USA).gba" size 4194304 crc 0ee82569 sha1 cde84171b11a767338158c61ee2ad608d4eb8889 flags verified ) ) game ( @@ -1764,18 +1866,18 @@ game ( rom ( name "Banjo-Pilot (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc b98de3a4 sha1 5203f49c3b372b49dcb5c23f0dcbbb8432336081 flags verified ) ) -game ( - name "Banjo-Pilot (Europe) (En,Fr,De,Es,It) (Beta 2) (2004-09-29)" - description "Banjo-Pilot (Europe) (En,Fr,De,Es,It) (Beta 2) (2004-09-29)" - rom ( name "Banjo-Pilot (Europe) (En,Fr,De,Es,It) (Beta 2) (2004-09-29).gba" size 16777216 crc 3168a9a4 sha1 d0d26e986f73300b52f2a91b0bd57f92d05dda31 ) -) - game ( name "Banjo-Pilot (Europe) (Beta 1)" description "Banjo-Pilot (Europe) (Beta 1)" rom ( name "Banjo-Pilot (Europe) (Beta 1).gba" size 15545696 crc 817fd31d sha1 51b7fe0af316f4c25e08b2c8348b579e86697e3f ) ) +game ( + name "Banjo-Pilot (Europe) (En,Fr,De,Es,It) (Beta 2) (2004-09-29)" + description "Banjo-Pilot (Europe) (En,Fr,De,Es,It) (Beta 2) (2004-09-29)" + rom ( name "Banjo-Pilot (Europe) (En,Fr,De,Es,It) (Beta 2) (2004-09-29).gba" size 16777216 crc 3168a9a4 sha1 d0d26e986f73300b52f2a91b0bd57f92d05dda31 ) +) + game ( name "Barbie - The Princess and the Pauper (USA)" description "Barbie - The Princess and the Pauper (USA)" @@ -1801,9 +1903,9 @@ game ( ) game ( - name "Barbie as the Island Princess (USA)" - description "Barbie as the Island Princess (USA)" - rom ( name "Barbie as the Island Princess (USA).gba" size 8388608 crc db6160eb sha1 4ac1502b9b292584beecb8c7baf1abbcdb3a2d75 ) + name "Barbie as The Island Princess (USA)" + description "Barbie as The Island Princess (USA)" + rom ( name "Barbie as The Island Princess (USA).gba" size 8388608 crc db6160eb sha1 4ac1502b9b292584beecb8c7baf1abbcdb3a2d75 ) ) game ( @@ -1818,18 +1920,6 @@ game ( rom ( name "Barbie Diaries, The - High School Mystery (Europe).gba" size 8388608 crc 4e8a650c sha1 1a89dc89d8cffc119643b99228d4cc567d5421b3 ) ) -game ( - name "Barbie Groovy Games (USA)" - description "Barbie Groovy Games (USA)" - rom ( name "Barbie Groovy Games (USA).gba" size 4194304 crc aa017567 sha1 055db9f8f3ba18358162a1411cf24300a6de6046 ) -) - -game ( - name "Barbie Groovy Games (Europe) (En,Fr,De,Es,It)" - description "Barbie Groovy Games (Europe) (En,Fr,De,Es,It)" - rom ( name "Barbie Groovy Games (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 749339b2 sha1 e41751c52d5cd84b204ac4d73eefc5b360f56f1d ) -) - game ( name "Barbie Horse Adventures (Europe) (En,Fr,De,Es,It,Nl)" description "Barbie Horse Adventures (Europe) (En,Fr,De,Es,It,Nl)" @@ -1851,7 +1941,19 @@ game ( game ( name "Barbie in the 12 Dancing Princesses (Europe) (En,Fr,De,Es,It)" description "Barbie in the 12 Dancing Princesses (Europe) (En,Fr,De,Es,It)" - rom ( name "Barbie in the 12 Dancing Princesses (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 7ca7aa12 sha1 3feb77f60ad71d4dbb83c7ea0712759e50ccc088 ) + rom ( name "Barbie in the 12 Dancing Princesses (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 7ca7aa12 sha1 3feb77f60ad71d4dbb83c7ea0712759e50ccc088 flags verified ) +) + +game ( + name "Barbie Software - Groovy Games (USA)" + description "Barbie Software - Groovy Games (USA)" + rom ( name "Barbie Software - Groovy Games (USA).gba" size 4194304 crc aa017567 sha1 055db9f8f3ba18358162a1411cf24300a6de6046 ) +) + +game ( + name "Barbie Software - Groovy Games (Europe) (En,Fr,De,Es,It)" + description "Barbie Software - Groovy Games (Europe) (En,Fr,De,Es,It)" + rom ( name "Barbie Software - Groovy Games (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 749339b2 sha1 e41751c52d5cd84b204ac4d73eefc5b360f56f1d flags verified ) ) game ( @@ -1927,69 +2029,75 @@ game ( ) game ( - name "Battle Network Rockman EXE (Japan)" - description "Battle Network Rockman EXE (Japan)" - rom ( name "Battle Network Rockman EXE (Japan).gba" size 8388608 crc d9516e50 sha1 6e42dbd5cdee25851fb55dba060b28e28e4f4e5f ) + name "Battle Network - Rockman EXE (Japan) (Virtual Console)" + description "Battle Network - Rockman EXE (Japan) (Virtual Console)" + rom ( name "Battle Network - Rockman EXE (Japan) (Virtual Console).gba" size 8388608 crc 109f133b sha1 7872a276d0059ff0bcff86fd3f843cace3cc8840 ) ) game ( - name "Battle Network Rockman EXE (Japan) (Virtual Console)" - description "Battle Network Rockman EXE (Japan) (Virtual Console)" - rom ( name "Battle Network Rockman EXE (Japan) (Virtual Console).gba" size 8388608 crc 109f133b sha1 7872a276d0059ff0bcff86fd3f843cace3cc8840 ) + name "Battle Network - Rockman EXE (Japan)" + description "Battle Network - Rockman EXE (Japan)" + rom ( name "Battle Network - Rockman EXE (Japan).gba" size 8388608 crc d9516e50 sha1 6e42dbd5cdee25851fb55dba060b28e28e4f4e5f ) ) game ( - name "Battle Network Rockman EXE 2 (Japan) (Rev 1) (Virtual Console)" - description "Battle Network Rockman EXE 2 (Japan) (Rev 1) (Virtual Console)" - rom ( name "Battle Network Rockman EXE 2 (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 44d44721 sha1 1c2416dfb86936752c5f68861f6339feac21458f ) + name "Battle Network - Rockman EXE 2 (Japan)" + description "Battle Network - Rockman EXE 2 (Japan)" + rom ( name "Battle Network - Rockman EXE 2 (Japan).gba" size 8388608 crc 98e4f096 sha1 6ed31ea56328673ba9d87186a7d506c701508e28 ) ) game ( - name "Battle Network Rockman EXE 2 (Japan) (Rev 1)" - description "Battle Network Rockman EXE 2 (Japan) (Rev 1)" - rom ( name "Battle Network Rockman EXE 2 (Japan) (Rev 1).gba" size 8388608 crc 41576087 sha1 9cb4d57bdedee5a760e98a3068c0e39a293b447c ) + name "Battle Network - Rockman EXE 2 (Japan) (Rev 1)" + description "Battle Network - Rockman EXE 2 (Japan) (Rev 1)" + rom ( name "Battle Network - Rockman EXE 2 (Japan) (Rev 1).gba" size 8388608 crc 41576087 sha1 9cb4d57bdedee5a760e98a3068c0e39a293b447c ) ) game ( - name "Battle Network Rockman EXE 2 (Japan)" - description "Battle Network Rockman EXE 2 (Japan)" - rom ( name "Battle Network Rockman EXE 2 (Japan).gba" size 8388608 crc 98e4f096 sha1 6ed31ea56328673ba9d87186a7d506c701508e28 ) + name "Battle Network - Rockman EXE 2 (Japan) (Rev 1) (Virtual Console)" + description "Battle Network - Rockman EXE 2 (Japan) (Rev 1) (Virtual Console)" + rom ( name "Battle Network - Rockman EXE 2 (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 44d44721 sha1 1c2416dfb86936752c5f68861f6339feac21458f ) ) game ( - name "Battle Network Rockman EXE 3 (Japan)" - description "Battle Network Rockman EXE 3 (Japan)" - rom ( name "Battle Network Rockman EXE 3 (Japan).gba" size 8388608 crc 1c57724e sha1 2a381543f84dacc0f8310d4516fde0c33b5feca0 ) + name "Battle Network - Rockman EXE 3 (Japan) (Rev 1) (Virtual Console)" + description "Battle Network - Rockman EXE 3 (Japan) (Rev 1) (Virtual Console)" + rom ( name "Battle Network - Rockman EXE 3 (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 47ccb9b8 sha1 e2a7c4abba66d17e073281e9ea44b6a5760b53c6 ) ) game ( - name "Battle Network Rockman EXE 3 (Japan) (Rev 1) (Virtual Console)" - description "Battle Network Rockman EXE 3 (Japan) (Rev 1) (Virtual Console)" - rom ( name "Battle Network Rockman EXE 3 (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 47ccb9b8 sha1 e2a7c4abba66d17e073281e9ea44b6a5760b53c6 ) + name "Battle Network - Rockman EXE 3 (Japan)" + description "Battle Network - Rockman EXE 3 (Japan)" + rom ( name "Battle Network - Rockman EXE 3 (Japan).gba" size 8388608 crc 1c57724e sha1 2a381543f84dacc0f8310d4516fde0c33b5feca0 ) ) game ( - name "Battle Network Rockman EXE 3 (Japan) (Rev 1)" - description "Battle Network Rockman EXE 3 (Japan) (Rev 1)" - rom ( name "Battle Network Rockman EXE 3 (Japan) (Rev 1).gba" size 8388608 crc e48e6bc9 sha1 87e0ab10541eaaa5e9c01f7fad822a3e1bf52278 ) + name "Battle Network - Rockman EXE 3 (Japan) (Rev 1)" + description "Battle Network - Rockman EXE 3 (Japan) (Rev 1)" + rom ( name "Battle Network - Rockman EXE 3 (Japan) (Rev 1).gba" size 8388608 crc e48e6bc9 sha1 87e0ab10541eaaa5e9c01f7fad822a3e1bf52278 ) ) game ( - name "Battle Network Rockman EXE 3 - Black (Japan) (Promo)" - description "Battle Network Rockman EXE 3 - Black (Japan) (Promo)" - rom ( name "Battle Network Rockman EXE 3 - Black (Japan) (Promo).gba" size 8388608 crc 1f13c41f sha1 ff65af8fea15ecf5a556595efe414d1211a9ab4e ) + name "Battle Network - Rockman EXE 3 - Black (Japan) (Promo)" + description "Battle Network - Rockman EXE 3 - Black (Japan) (Promo)" + rom ( name "Battle Network - Rockman EXE 3 - Black (Japan) (Promo).gba" size 8388608 crc 1f13c41f sha1 ff65af8fea15ecf5a556595efe414d1211a9ab4e ) ) game ( - name "Battle Network Rockman EXE 3 - Black (Japan) (Rev 1)" - description "Battle Network Rockman EXE 3 - Black (Japan) (Rev 1)" - rom ( name "Battle Network Rockman EXE 3 - Black (Japan) (Rev 1).gba" size 8388608 crc fd57493b sha1 e089a2254496a4791666c8122585cb785e3012fc ) + name "Battle Network - Rockman EXE 3 - Black (Japan) (Rev 1) (Virtual Console)" + description "Battle Network - Rockman EXE 3 - Black (Japan) (Rev 1) (Virtual Console)" + rom ( name "Battle Network - Rockman EXE 3 - Black (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 93e89735 sha1 42ed01e9c8fdc0ea7c0703c821322bd196c66be4 ) ) game ( - name "Battle Network Rockman EXE 3 - Black (Japan) (Rev 1) (Virtual Console)" - description "Battle Network Rockman EXE 3 - Black (Japan) (Rev 1) (Virtual Console)" - rom ( name "Battle Network Rockman EXE 3 - Black (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 93e89735 sha1 42ed01e9c8fdc0ea7c0703c821322bd196c66be4 ) + name "Battle Network - Rockman EXE 3 - Black (Japan) (Rev 1)" + description "Battle Network - Rockman EXE 3 - Black (Japan) (Rev 1)" + rom ( name "Battle Network - Rockman EXE 3 - Black (Japan) (Rev 1).gba" size 8388608 crc fd57493b sha1 e089a2254496a4791666c8122585cb785e3012fc ) +) + +game ( + name "Battle Picross (World) (Unl)" + description "Battle Picross (World) (Unl)" + rom ( name "Battle Picross (World) (Unl).gba" size 194784 crc 7f36d6f0 sha1 7431f36c68bba7ad42301b395e1237445f059a9e ) ) game ( @@ -2040,6 +2148,12 @@ game ( rom ( name "Bee Game, The (USA).gba" size 4194304 crc da747c99 sha1 3a073625e7d0f844b940d0d8a71216cdce335a47 ) ) +game ( + name "Bengt Swinger of Longarm (World) (Unl)" + description "Bengt Swinger of Longarm (World) (Unl)" + rom ( name "Bengt Swinger of Longarm (World) (Unl).gba" size 434844 crc e514de30 sha1 5ce8574548fe0ebd587eddf974f837b44a2d3c6c ) +) + game ( name "Berenstain Bears and the Spooky Old Tree, The (USA)" description "Berenstain Bears and the Spooky Old Tree, The (USA)" @@ -2262,6 +2376,12 @@ game ( rom ( name "Bleach Advance - Kurenai ni Somaru Soul Society (Japan).gba" size 33554432 crc 9de5cd08 sha1 29d24c38d3ec8bbe9d81df2f5ff61c4a2dadcee4 ) ) +game ( + name "Blender Bros. (World) (Aftermarket) (Unl)" + description "Blender Bros. (World) (Aftermarket) (Unl)" + rom ( name "Blender Bros. (World) (Aftermarket) (Unl).gba" size 8388608 crc 440f2f06 sha1 8f9ca62306b7ab56d8da45673d7b7d0eb4c349c5 ) +) + game ( name "Blender Bros. (USA)" description "Blender Bros. (USA)" @@ -2283,7 +2403,7 @@ game ( game ( name "BMX Trick Racer (USA)" description "BMX Trick Racer (USA)" - rom ( name "BMX Trick Racer (USA).gba" size 16777216 crc b6d79476 sha1 3a42d3331e81e92d49e285b36ae1a6ed5db6a2ea ) + rom ( name "BMX Trick Racer (USA).gba" size 16777216 crc b6d79476 sha1 3a42d3331e81e92d49e285b36ae1a6ed5db6a2ea flags verified ) ) game ( @@ -2322,12 +2442,6 @@ game ( rom ( name "Boboboubo Boubobo - Ougi 87.5 Bakuretsu Hanage Shinken (Japan).gba" size 8388608 crc 58105f89 sha1 c93fd22bb10e26cb986161ce1cdc4c2acb38add9 ) ) -game ( - name "Boktai - The Sun Is in Your Hand (USA) (Sample)" - description "Possibly a version given out to press at E3 or an E3 demo" - rom ( name "Boktai - The Sun Is in Your Hand (USA) (Sample).gba" size 16777216 crc cf692572 sha1 f91126cd3a1bf7bf5f770d3a70229171d0d5a6ee ) -) - game ( name "Boktai - The Sun Is in Your Hand (USA)" description "Boktai - The Sun Is in Your Hand (USA)" @@ -2340,6 +2454,12 @@ game ( rom ( name "Boktai - The Sun Is in Your Hand (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 9686c36b sha1 64f7bf0f0560f6e94da33b549d3206678b29f557 flags verified ) ) +game ( + name "Boktai - The Sun Is in Your Hand (USA) (Sample)" + description "Possibly a version given out to press at E3 or an E3 demo" + rom ( name "Boktai - The Sun Is in Your Hand (USA) (Sample).gba" size 16777216 crc cf692572 sha1 f91126cd3a1bf7bf5f770d3a70229171d0d5a6ee ) +) + game ( name "Boktai 2 - Solar Boy Django (USA)" description "Boktai 2 - Solar Boy Django (USA)" @@ -2445,7 +2565,7 @@ game ( game ( name "Bouken Yuuki Pluster World - Densetsu no Plust Gate (Japan)" description "Bouken Yuuki Pluster World - Densetsu no Plust Gate (Japan)" - rom ( name "Bouken Yuuki Pluster World - Densetsu no Plust Gate (Japan).gba" size 8388608 crc 57438e39 sha1 bb779de3aa9c08b82ffcb3cb2eb70f151a8a3b13 ) + rom ( name "Bouken Yuuki Pluster World - Densetsu no Plust Gate (Japan).gba" size 8388608 crc 57438e39 sha1 bb779de3aa9c08b82ffcb3cb2eb70f151a8a3b13 flags verified ) ) game ( @@ -2491,9 +2611,9 @@ game ( ) game ( - name "Bounty Hunter X (Europe) (Unl)" - description "Bounty Hunter X (Europe) (Unl)" - rom ( name "Bounty Hunter X (Europe) (Unl).gba" size 304344 crc 91344285 sha1 6e39d034ccf318a17a8bd044dd58bc31f4ba2ab9 ) + name "Bounty Hunter X (World) (Unl)" + description "Bounty Hunter X (World) (Unl)" + rom ( name "Bounty Hunter X (World) (Unl).gba" size 304344 crc 91344285 sha1 6e39d034ccf318a17a8bd044dd58bc31f4ba2ab9 flags verified ) ) game ( @@ -2595,13 +2715,13 @@ game ( game ( name "Breath of Fire (Europe)" description "Breath of Fire (Europe)" - rom ( name "Breath of Fire (Europe).gba" size 4194304 crc a1c3165d sha1 f47870d25665588d19b75e90d0bd32a759e64918 ) + rom ( name "Breath of Fire (Europe).gba" size 4194304 crc a1c3165d sha1 f47870d25665588d19b75e90d0bd32a759e64918 flags verified ) ) game ( name "Breath of Fire (USA)" description "Breath of Fire (USA)" - rom ( name "Breath of Fire (USA).gba" size 4194304 crc f06422a8 sha1 b30533f68037b47d5439bab0182169e4a643a38d ) + rom ( name "Breath of Fire (USA).gba" size 4194304 crc f06422a8 sha1 b30533f68037b47d5439bab0182169e4a643a38d flags verified ) ) game ( @@ -2661,7 +2781,7 @@ game ( game ( name "Broken Circle (Europe) (En,It) (Proto)" description "Broken Circle (Europe) (En,It) (Proto)" - rom ( name "Broken Circle (Europe) (En,It) (Proto).gba" size 8388608 crc 1e8f8ae0 sha1 fec9fda1c776ac9bb87a609d0be1effe7ea158b6 ) + rom ( name "Broken Circle (Europe) (En,It) (Proto).gba" size 8409344 crc e78bc690 sha1 d015a5039ff5d08eeba3ddb16470eaab259631d0 ) ) game ( @@ -2790,18 +2910,18 @@ game ( rom ( name "Cabela's Big Game Hunter - 2005 Adventures (USA, Europe).gba" size 4194304 crc bd054567 sha1 aff3c5bc948c2c868be7da8a327aee25beaa027c flags verified ) ) -game ( - name "Caesars Palace Advance - Millennium Gold Edition (USA) (Beta)" - description "Caesars Palace Advance - Millennium Gold Edition (USA) (Beta)" - rom ( name "Caesars Palace Advance - Millennium Gold Edition (USA) (Beta).gba" size 4194304 crc 13dc0731 sha1 1a89cecd9bf89df42ae4ef35d17d437b17e53c80 ) -) - game ( name "Caesars Palace Advance - Millennium Gold Edition (USA, Europe)" description "Caesars Palace Advance - Millennium Gold Edition (USA, Europe)" rom ( name "Caesars Palace Advance - Millennium Gold Edition (USA, Europe).gba" size 8388608 crc 5d54ece5 sha1 cd5dbb8b8361ca5d003ec496a99351020dabc329 ) ) +game ( + name "Caesars Palace Advance - Millennium Gold Edition (USA, Europe) (Beta)" + description "Caesars Palace Advance - Millennium Gold Edition (USA, Europe) (Beta)" + rom ( name "Caesars Palace Advance - Millennium Gold Edition (USA, Europe) (Beta).gba" size 4194304 crc 13dc0731 sha1 1a89cecd9bf89df42ae4ef35d17d437b17e53c80 ) +) + game ( name "Calciobit (Japan)" description "Calciobit (Japan)" @@ -2847,7 +2967,7 @@ game ( game ( name "Card e-Reader+ (Japan)" description "Card e-Reader+ (Japan)" - rom ( name "Card e-Reader+ (Japan).gba" size 8388608 crc 4139e7c3 sha1 2af41785dd72c664e8a1c0f1e1ce0edcd105dd5e ) + rom ( name "Card e-Reader+ (Japan).gba" size 8388608 crc 4139e7c3 sha1 2af41785dd72c664e8a1c0f1e1ce0edcd105dd5e flags verified ) ) game ( @@ -2875,15 +2995,15 @@ game ( ) game ( - name "Care Bears - The Care Quests (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" - description "Care Bears - The Care Quests (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" - rom ( name "Care Bears - The Care Quests (Europe) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 4194304 crc 6111ed1e sha1 606ad547286fdf14cc0fe60e5c34f9db83a059dc ) + name "Care Bears - The Care Quest (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + description "Care Bears - The Care Quest (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" + rom ( name "Care Bears - The Care Quest (Europe) (En,Fr,De,Es,It,Nl,Pt,Da).gba" size 4194304 crc 6111ed1e sha1 606ad547286fdf14cc0fe60e5c34f9db83a059dc ) ) game ( - name "Care Bears - The Care Quests (USA) (En,Fr,Es)" - description "Care Bears - The Care Quests (USA) (En,Fr,Es)" - rom ( name "Care Bears - The Care Quests (USA) (En,Fr,Es).gba" size 4194304 crc f848c327 sha1 750eb05960ace3bd38c6e362a0f6970ac3371964 ) + name "Care Bears - The Care Quest (USA) (En,Fr,Es)" + description "Care Bears - The Care Quest (USA) (En,Fr,Es)" + rom ( name "Care Bears - The Care Quest (USA) (En,Fr,Es).gba" size 4194304 crc f848c327 sha1 750eb05960ace3bd38c6e362a0f6970ac3371964 ) ) game ( @@ -3126,6 +3246,12 @@ game ( rom ( name "Cat in the Hat, The (USA).gba" size 4194304 crc 13c2249e sha1 9340482db02bf5263429a15798d06c509017aa93 ) ) +game ( + name "Cat's Curse (World) (Aftermarket) (Unl)" + description "Cat's Curse (World) (Aftermarket) (Unl)" + rom ( name "Cat's Curse (World) (Aftermarket) (Unl).gba" size 353052 crc a35d87de sha1 4a149baad17840948c2d4ffdf068bfaf1116a024 ) +) + game ( name "Catwoman (USA, Europe) (En,Fr,De,Es,It,Nl)" description "Catwoman (USA, Europe) (En,Fr,De,Es,It,Nl)" @@ -3145,21 +3271,21 @@ game ( ) game ( - name "Celeste Classic (World) (v1.0) (Aftermarket) (Homebrew)" - description "Celeste Classic (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Celeste Classic (World) (v1.0) (Aftermarket) (Homebrew).gba" size 5416932 crc f79b0d53 sha1 756f02396a150698e695ad4afd24445e2af70576 ) + name "Celeste Classic (World) (v1.0) (Aftermarket) (Unl)" + description "Celeste Classic (World) (v1.0) (Aftermarket) (Unl)" + rom ( name "Celeste Classic (World) (v1.0) (Aftermarket) (Unl).gba" size 5416932 crc f79b0d53 sha1 756f02396a150698e695ad4afd24445e2af70576 ) ) game ( - name "Celeste Classic (World) (v1.1) (Aftermarket) (Homebrew)" - description "Celeste Classic (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Celeste Classic (World) (v1.1) (Aftermarket) (Homebrew).gba" size 5418248 crc f5d36ad2 sha1 95a86dff641b11b4c2ed0d0fe8152c33b462d927 ) + name "Celeste Classic (World) (v1.1) (Aftermarket) (Unl)" + description "Celeste Classic (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Celeste Classic (World) (v1.1) (Aftermarket) (Unl).gba" size 5418248 crc f5d36ad2 sha1 95a86dff641b11b4c2ed0d0fe8152c33b462d927 ) ) game ( - name "Celeste Classic (World) (v1.2) (Aftermarket) (Homebrew)" - description "Celeste Classic (World) (v1.2) (Aftermarket) (Homebrew)" - rom ( name "Celeste Classic (World) (v1.2) (Aftermarket) (Homebrew).gba" size 5418424 crc ff0e8ada sha1 08512605e5c02e81a72e24c2c8d4959d8e84e1f4 ) + name "Celeste Classic (World) (v1.2) (Aftermarket) (Unl)" + description "Celeste Classic (World) (v1.2) (Aftermarket) (Unl)" + rom ( name "Celeste Classic (World) (v1.2) (Aftermarket) (Unl).gba" size 5418424 crc ff0e8ada sha1 08512605e5c02e81a72e24c2c8d4959d8e84e1f4 ) ) game ( @@ -3301,9 +3427,9 @@ game ( ) game ( - name "Chopper 2 The Return (Europe) (Unl)" - description "Chopper 2 The Return (Europe) (Unl)" - rom ( name "Chopper 2 The Return (Europe) (Unl).gba" size 861720 crc f33aac43 sha1 50c0eb0f3832a068bb9591d4dfaa8e1389bb87db ) + name "Chopper 2 - The Return (World) (Unl)" + description "Chopper 2 - The Return (World) (Unl)" + rom ( name "Chopper 2 - The Return (World) (Unl).gba" size 861720 crc f33aac43 sha1 50c0eb0f3832a068bb9591d4dfaa8e1389bb87db ) ) game ( @@ -3375,7 +3501,7 @@ game ( game ( name "Cinderella - Magical Dreams (USA) (En,Fr,De,Es,It)" description "Cinderella - Magical Dreams (USA) (En,Fr,De,Es,It)" - rom ( name "Cinderella - Magical Dreams (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 22f19169 sha1 1682d023933bf758c78ce2c18b503efd4f0803b9 ) + rom ( name "Cinderella - Magical Dreams (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 22f19169 sha1 1682d023933bf758c78ce2c18b503efd4f0803b9 flags verified ) ) game ( @@ -3423,7 +3549,7 @@ game ( game ( name "Classic NES Series - Dr. Mario (USA, Europe)" description "Classic NES Series - Dr. Mario (USA, Europe)" - rom ( name "Classic NES Series - Dr. Mario (USA, Europe).gba" size 1048576 crc 934e1f1d sha1 fc396f0eae55cf19e573aa322f525427e03d3854 flags verified ) + rom ( name "Classic NES Series - Dr. Mario (USA, Europe).gba" size 1048576 crc 934e1f1d sha1 fc396f0eae55cf19e573aa322f525427e03d3854 ) ) game ( @@ -3609,7 +3735,7 @@ game ( game ( name "Crash & Spyro Super Pack Volume 1 (Europe) (En,Fr,De,Es,It,Nl)" description "Crash & Spyro Super Pack Volume 1 (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Crash & Spyro Super Pack Volume 1 (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc d8382427 sha1 4e184f8f52e5a6b79a272f7674178d3d3ccc3386 ) + rom ( name "Crash & Spyro Super Pack Volume 1 (Europe) (En,Fr,De,Es,It,Nl).gba" size 16777216 crc d8382427 sha1 4e184f8f52e5a6b79a272f7674178d3d3ccc3386 flags verified ) ) game ( @@ -3621,7 +3747,7 @@ game ( game ( name "Crash & Spyro Super Pack Volume 3 (Europe) (En,Fr,De,Es,It)" description "Crash & Spyro Super Pack Volume 3 (Europe) (En,Fr,De,Es,It)" - rom ( name "Crash & Spyro Super Pack Volume 3 (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc 0510b70f sha1 bf33976d1a26e336416e0fd28b2b8da65450737d ) + rom ( name "Crash & Spyro Super Pack Volume 3 (Europe) (En,Fr,De,Es,It).gba" size 33554432 crc c7269e6a sha1 ec25e705d5129a97b405b6b15197cbb9141e135f flags verified ) ) game ( @@ -3645,7 +3771,7 @@ game ( game ( name "Crash Bandicoot - The Huge Adventure (USA)" description "Crash Bandicoot - The Huge Adventure (USA)" - rom ( name "Crash Bandicoot - The Huge Adventure (USA).gba" size 8388608 crc 034d2d4b sha1 5a2651c78bb8a1d707e3c3af1f46fb64e2104198 ) + rom ( name "Crash Bandicoot - The Huge Adventure (USA).gba" size 8388608 crc 034d2d4b sha1 5a2651c78bb8a1d707e3c3af1f46fb64e2104198 flags verified ) ) game ( @@ -3717,7 +3843,7 @@ game ( game ( name "Crash Nitro Kart (Europe) (En,Fr,De,Es,It,Nl)" description "Crash Nitro Kart (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Crash Nitro Kart (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 03925772 sha1 91904f5ba5c501b761fc01a48e4efc41ee5b8e41 ) + rom ( name "Crash Nitro Kart (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 03925772 sha1 91904f5ba5c501b761fc01a48e4efc41ee5b8e41 flags verified ) ) game ( @@ -3859,9 +3985,9 @@ game ( ) game ( - name "Cruis'n Velocity (USA) (Beta)" - description "Cruis'n Velocity (USA) (Beta)" - rom ( name "Cruis'n Velocity (USA) (Beta).gba" size 8388608 crc 5436d5da sha1 d1716d4603dd8db7ae8715d5142a60230d17e1d2 ) + name "Cruis'n Velocity (USA, Europe) (Beta)" + description "Cruis'n Velocity (USA, Europe) (Beta)" + rom ( name "Cruis'n Velocity (USA, Europe) (Beta).gba" size 8388608 crc 5436d5da sha1 d1716d4603dd8db7ae8715d5142a60230d17e1d2 ) ) game ( @@ -3900,18 +4026,18 @@ game ( rom ( name "CT Special Forces - Back to Hell (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 863cbf31 sha1 b782dac774932d93c313b122ca2c7c072ca84840 ) ) -game ( - name "CT Special Forces - Bioterror (Europe) (En,Fr,De,Es,It,Nl)" - description "CT Special Forces - Bioterror (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "CT Special Forces - Bioterror (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 7dc40eda sha1 0ac478e4568f5886fce546b903fd50424a059438 ) -) - game ( name "CT Special Forces 2 - Back in the Trenches (USA) (En,Fr,De,Es,It,Nl)" description "CT Special Forces 2 - Back in the Trenches (USA) (En,Fr,De,Es,It,Nl)" rom ( name "CT Special Forces 2 - Back in the Trenches (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc d2b58a33 sha1 cedca3aac39309dc122909d11457e306c81e16be ) ) +game ( + name "CT Special Forces 3 - Bioterror (Europe) (En,Fr,De,Es,It,Nl)" + description "CT Special Forces 3 - Bioterror (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "CT Special Forces 3 - Bioterror (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 7dc40eda sha1 0ac478e4568f5886fce546b903fd50424a059438 ) +) + game ( name "Cubix - Robots for Everyone - Clash 'N Bash (USA)" description "Cubix - Robots for Everyone - Clash 'N Bash (USA)" @@ -3948,6 +4074,12 @@ game ( rom ( name "Dai-mahjong. (Japan).gba" size 4194304 crc c6ccca05 sha1 35e4c69a6a30362d873e3383942f86932a216ecf ) ) +game ( + name "Daigassou! Band-Brothers - Request Selection (Japan) (DS Expansion Cartridge)" + description "Daigassou! Band-Brothers - Request Selection (Japan) (DS Expansion Cartridge)" + rom ( name "Daigassou! Band-Brothers - Request Selection (Japan) (DS Expansion Cartridge).gba" size 1048576 crc 374de320 sha1 5cb5af28b3b6a0fd7a0bff4a800f28c9e3727194 ) +) + game ( name "Daisenryaku for Game Boy Advance (Japan)" description "Daisenryaku for Game Boy Advance (Japan)" @@ -4011,7 +4143,7 @@ game ( game ( name "Daredevil (USA, Europe)" description "Daredevil (USA, Europe)" - rom ( name "Daredevil (USA, Europe).gba" size 4194304 crc d438347e sha1 db2bb397b47f1ff247dad5cfa6e35866b1048a7b ) + rom ( name "Daredevil (USA, Europe).gba" size 4194304 crc d438347e sha1 db2bb397b47f1ff247dad5cfa6e35866b1048a7b flags verified ) ) game ( @@ -4065,7 +4197,7 @@ game ( game ( name "Dave Mirra Freestyle BMX 3 (USA, Europe)" description "Dave Mirra Freestyle BMX 3 (USA, Europe)" - rom ( name "Dave Mirra Freestyle BMX 3 (USA, Europe).gba" size 8388608 crc 8d8f26a5 sha1 dcce47b536ace90a918d94d06698c92538d7e4d1 ) + rom ( name "Dave Mirra Freestyle BMX 3 (USA, Europe).gba" size 8388608 crc 8d8f26a5 sha1 dcce47b536ace90a918d94d06698c92538d7e4d1 flags verified ) ) game ( @@ -4143,13 +4275,13 @@ game ( game ( name "DemiKids - Dark Version (USA)" description "DemiKids - Dark Version (USA)" - rom ( name "DemiKids - Dark Version (USA).gba" size 8388608 crc 1bab58bd sha1 f3dbc8c6d58c33b88c28306f54ff742da1c8d6c9 ) + rom ( name "DemiKids - Dark Version (USA).gba" size 8388608 crc 1bab58bd sha1 f3dbc8c6d58c33b88c28306f54ff742da1c8d6c9 flags verified ) ) game ( name "DemiKids - Light Version (USA)" description "DemiKids - Light Version (USA)" - rom ( name "DemiKids - Light Version (USA).gba" size 8388608 crc dc4357c4 sha1 8bc80eb5f08bfa83597483390b18092d9a12700d ) + rom ( name "DemiKids - Light Version (USA).gba" size 8388608 crc dc4357c4 sha1 8bc80eb5f08bfa83597483390b18092d9a12700d flags verified ) ) game ( @@ -4269,7 +4401,7 @@ game ( game ( name "Di Gi Charat - DigiCommunication (Japan)" description "Di Gi Charat - DigiCommunication (Japan)" - rom ( name "Di Gi Charat - DigiCommunication (Japan).gba" size 8388608 crc a1288427 sha1 35f9fa0305de3382aa6fb01f14baa9419ffa5349 ) + rom ( name "Di Gi Charat - DigiCommunication (Japan).gba" size 8388608 crc a1288427 sha1 35f9fa0305de3382aa6fb01f14baa9419ffa5349 flags verified ) ) game ( @@ -4299,7 +4431,7 @@ game ( game ( name "Digimon - Battle Spirit (Europe) (En,Fr,De,Es,It)" description "Digimon - Battle Spirit (Europe) (En,Fr,De,Es,It)" - rom ( name "Digimon - Battle Spirit (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc ea5fc3da sha1 ecf0e597839905c9f23c6d568c79fc00c2719f49 ) + rom ( name "Digimon - Battle Spirit (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc ea5fc3da sha1 ecf0e597839905c9f23c6d568c79fc00c2719f49 flags verified ) ) game ( @@ -4548,6 +4680,18 @@ game ( rom ( name "DK - King of Swing (USA) (Demo) (Kiosk).gba" size 8388608 crc 049626d1 sha1 d704ea9311c6ac9773bb70181de86ba0843583fd ) ) +game ( + name "Dog Trainer (Europe) (DS Cheat Cartridge) (Unl)" + description "Dog Trainer (Europe) (DS Cheat Cartridge) (Unl)" + rom ( name "Dog Trainer (Europe) (DS Cheat Cartridge) (Unl).gba" size 1048576 crc 6b3961fb sha1 6994b43605a14f64b7b1ad2f4ba93f216342b9e1 ) +) + +game ( + name "Dog Trainer 2 (Europe) (DS Cheat Cartridge) (Unl)" + description "Dog Trainer 2 (Europe) (DS Cheat Cartridge) (Unl)" + rom ( name "Dog Trainer 2 (Europe) (DS Cheat Cartridge) (Unl).gba" size 1048576 crc b2100fed sha1 812475fcb025a7a216f4544605e9110759d8b02e ) +) + game ( name "Dogz (USA)" description "Dogz (USA)" @@ -4656,6 +4800,12 @@ game ( rom ( name "Domo-kun no Fushigi Television (Japan).gba" size 8388608 crc e743c611 sha1 c5c70840c6222c52a2e814d106ab1f2478cd5cab ) ) +game ( + name "Don-chan Puzzle - Hanabi de Doon! Advance (Japan)" + description "Don-chan Puzzle - Hanabi de Doon! Advance (Japan)" + rom ( name "Don-chan Puzzle - Hanabi de Doon! Advance (Japan).gba" size 8388608 crc 500922e8 sha1 5598e6143dd0dab1793507317624973557f35568 ) +) + game ( name "Donald Duck Advance (Europe) (En,Fr,De,Es,It)" description "Donald Duck Advance (Europe) (En,Fr,De,Es,It)" @@ -4674,30 +4824,24 @@ game ( rom ( name "Donald Duck Advance (USA).gba" size 8388608 crc 936daab2 sha1 020081ad9dda023adf604b790ddfc95fcf2a7835 ) ) -game ( - name "Donchan Puzzle - Hanabi de Dohn! Advance (Japan)" - description "Donchan Puzzle - Hanabi de Dohn! Advance (Japan)" - rom ( name "Donchan Puzzle - Hanabi de Dohn! Advance (Japan).gba" size 8388608 crc 500922e8 sha1 5598e6143dd0dab1793507317624973557f35568 ) -) - game ( name "Donkey Kong 2 (USA) (Unl)" description "Donkey Kong 2 (USA) (Unl)" rom ( name "Donkey Kong 2 (USA) (Unl).gba" size 33554432 crc 006a6afa sha1 b62e1625416f67981cb834c8428603f7800fee5b ) ) -game ( - name "Donkey Kong Country (Europe) (En,Fr,De,Es,It)" - description "Donkey Kong Country (Europe) (En,Fr,De,Es,It)" - rom ( name "Donkey Kong Country (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 41d277fe sha1 8995f0be99a9cff66474a8975b8499bd69fb4c45 flags verified ) -) - game ( name "Donkey Kong Country (USA)" description "Donkey Kong Country (USA)" rom ( name "Donkey Kong Country (USA).gba" size 8388608 crc 12f7a968 sha1 fcc62356a3b7157ca7dda1398c9bf1af1dd31265 flags verified ) ) +game ( + name "Donkey Kong Country (Europe) (En,Fr,De,Es,It)" + description "Donkey Kong Country (Europe) (En,Fr,De,Es,It)" + rom ( name "Donkey Kong Country (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 41d277fe sha1 8995f0be99a9cff66474a8975b8499bd69fb4c45 flags verified ) +) + game ( name "Donkey Kong Country 2 (Europe) (En,Fr,De,Es,It)" description "Donkey Kong Country 2 (Europe) (En,Fr,De,Es,It)" @@ -4707,7 +4851,7 @@ game ( game ( name "Donkey Kong Country 2 (USA)" description "Donkey Kong Country 2 (USA)" - rom ( name "Donkey Kong Country 2 (USA).gba" size 8388608 crc 11417fc1 sha1 b0a4d59447c8d7c321bea4dc7253b0f581129ede ) + rom ( name "Donkey Kong Country 2 (USA).gba" size 8388608 crc 11417fc1 sha1 b0a4d59447c8d7c321bea4dc7253b0f581129ede flags verified ) ) game ( @@ -4728,6 +4872,12 @@ game ( rom ( name "Donkey Kong Country 3 (USA).gba" size 16777216 crc fe03e5af sha1 c50982b4c26e25ba3538be97b585d95737d7ade7 flags verified ) ) +game ( + name "Donsol (World) (Aftermarket) (Unl)" + description "Donsol (World) (Aftermarket) (Unl)" + rom ( name "Donsol (World) (Aftermarket) (Unl).gba" size 52520 crc aec144b3 sha1 751675b0d77c341f2265b0edd38858b0dbdb7b50 ) +) + game ( name "Doom (USA, Europe)" description "Doom (USA, Europe)" @@ -4737,7 +4887,7 @@ game ( game ( name "Doom II (USA)" description "Doom II (USA)" - rom ( name "Doom II (USA).gba" size 16777216 crc c885d9e9 sha1 2feeffc96386cf2cc0b2076928b010f18e9e9748 ) + rom ( name "Doom II (USA).gba" size 16777216 crc c885d9e9 sha1 2feeffc96386cf2cc0b2076928b010f18e9e9748 flags verified ) ) game ( @@ -4917,13 +5067,7 @@ game ( game ( name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It)" description "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It)" - rom ( name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 6c135820 sha1 e49ae836b14f84dc8cd817bf912fcdce82d8a587 ) -) - -game ( - name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It) (Beta) (2005-02-25)" - description "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It) (Beta) (2005-02-25)" - rom ( name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It) (Beta) (2005-02-25).gba" size 16777216 crc 2b136906 sha1 fe190755f05994f1c796286ad767d7da49c36385 ) + rom ( name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 6c135820 sha1 e49ae836b14f84dc8cd817bf912fcdce82d8a587 flags verified ) ) game ( @@ -4932,6 +5076,12 @@ game ( rom ( name "Dragon Ball - Advanced Adventure (USA).gba" size 16777216 crc 7d7306df sha1 1338584d8cfa57402603197e65d2e2ff0184d24f ) ) +game ( + name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It) (Beta) (2005-02-25)" + description "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It) (Beta) (2005-02-25)" + rom ( name "Dragon Ball - Advanced Adventure (Europe) (En,Fr,De,Es,It) (Beta) (2005-02-25).gba" size 16777216 crc 2b136906 sha1 fe190755f05994f1c796286ad767d7da49c36385 ) +) + game ( name "Dragon Ball GT - Transformation (USA)" description "Dragon Ball GT - Transformation (USA)" @@ -4995,7 +5145,7 @@ game ( game ( name "Dragon Ball Z - Taiketsu (USA)" description "Dragon Ball Z - Taiketsu (USA)" - rom ( name "Dragon Ball Z - Taiketsu (USA).gba" size 8388608 crc 64ec07e7 sha1 1fac4e187b8cf0aeb218ca307f10955f432d258d ) + rom ( name "Dragon Ball Z - Taiketsu (USA).gba" size 8388608 crc 64ec07e7 sha1 1fac4e187b8cf0aeb218ca307f10955f432d258d flags verified ) ) game ( @@ -5049,7 +5199,7 @@ game ( game ( name "Dragon Quest Characters - Torneko no Daibouken 3 Advance - Fushigi no Dungeon (Japan)" description "Dragon Quest Characters - Torneko no Daibouken 3 Advance - Fushigi no Dungeon (Japan)" - rom ( name "Dragon Quest Characters - Torneko no Daibouken 3 Advance - Fushigi no Dungeon (Japan).gba" size 16777216 crc c891b2a0 sha1 f306ce96404cff93caee78c86696a69b431b289a ) + rom ( name "Dragon Quest Characters - Torneko no Daibouken 3 Advance - Fushigi no Dungeon (Japan).gba" size 16777216 crc c891b2a0 sha1 f306ce96404cff93caee78c86696a69b431b289a flags verified ) ) game ( @@ -5448,6 +5598,12 @@ game ( rom ( name "Elf Bowling 1 & 2 (USA).gba" size 4194304 crc 68feff40 sha1 013f128c8d67f1165196b4f29297bcd4616c5033 ) ) +game ( + name "Elland - The Crystal Wars (World) (Digital Release) (Aftermarket) (Unl)" + description "Elland - The Crystal Wars (World) (Digital Release) (Aftermarket) (Unl)" + rom ( name "Elland - The Crystal Wars (World) (Digital Release) (Aftermarket) (Unl).gba" size 4016344 crc e3128bcb sha1 67617136f205fa071d9fc239df09471e603c675c ) +) + game ( name "Enchanted - Once Upon Andalasia (USA) (En,Fr)" description "Enchanted - Once Upon Andalasia (USA) (En,Fr)" @@ -5713,9 +5869,81 @@ game ( ) game ( - name "F-Zero - Maximum Velocity (USA, Europe) (Virtual Console)" - description "F-Zero - Maximum Velocity (USA, Europe) (Virtual Console)" - rom ( name "F-Zero - Maximum Velocity (USA, Europe) (Virtual Console).gba" size 4194304 crc 4b5f1cdd sha1 bd08e426c743c7429efd576ce0ef00a70cffd72a flags verified ) + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-29) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-29) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-29) (Netcard).gba" size 16777216 crc d329df50 sha1 71b626b355813e80f9cc3d6ae3765552b5e09009 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-26) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-26) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-26) (Netcard).gba" size 16777216 crc c77188b6 sha1 377f0f17ce3cea637dfdf9021f04aa56971db6a6 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-24) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-24) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-24) (Netcard).gba" size 16777216 crc 77c0c615 sha1 bfe6b7f099998edf6e35bc47dfd86c1e88152cb4 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-23) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-23) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-23) (Netcard).gba" size 16777216 crc 4d224e17 sha1 685753aa1bff5ed077eaa01ab058fa800b9c50c7 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-18 23.00.14) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-18 23.00.14) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-18 23.00.14) (Netcard).gba" size 16777216 crc 6f7486d7 sha1 3633a74b5fbed1a129f2ff37f7fd000c70b23a4d ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-18 02.40.54) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-18 02.40.54) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-18 02.40.54) (Netcard).gba" size 16777216 crc 27c8a067 sha1 54fa13e875c899dab0de270f334c283d3f5bb05c ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-17) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-17) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-17) (Netcard).gba" size 16777216 crc e73c5f4a sha1 8397fb78936dd667d0ef45b055613795df4a1c0e ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-16) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-16) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-16) (Netcard).gba" size 16777216 crc aa522f27 sha1 d8d9035e5672cb95fcd49499d5e4e7b6d6daad67 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-15) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-15) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-15) (Netcard).gba" size 16777216 crc 7ec47244 sha1 c8ca3281e9b329d967e96516f98744226f18974a ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-11) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-11) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-11) (Netcard).gba" size 16777216 crc debc0acb sha1 2d46237c002846b3a5cd1ed3daa173ebcf8e35f2 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-09) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-08-09) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-08-09) (Netcard).gba" size 16777216 crc c46fd22a sha1 2319499d453179763fc607ffbfe2d24a272237f3 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-09-02 00.17.57) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-09-02 00.17.57) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-09-02 00.17.57) (Netcard).gba" size 16777216 crc 61f9dc0e sha1 a9c26c71373bfa19c578591fd774f66644c0bdf2 ) +) + +game ( + name "F-Zero - GP Legend (Unknown) (Proto) (2005-09-02 01.21.24) (Netcard)" + description "F-Zero - GP Legend (Unknown) (Proto) (2005-09-02 01.21.24) (Netcard)" + rom ( name "F-Zero - GP Legend (Unknown) (Proto) (2005-09-02 01.21.24) (Netcard).gba" size 16777216 crc 26358b01 sha1 32d0b25c339f814c2840e289b232f38678b88193 ) ) game ( @@ -5725,9 +5953,9 @@ game ( ) game ( - name "F-Zero for Game Boy Advance (Japan)" - description "F-Zero for Game Boy Advance (Japan)" - rom ( name "F-Zero for Game Boy Advance (Japan).gba" size 4194304 crc 25e3fc9a sha1 cd8648b7158cf7c979cc05dea4c1aa927496e8b7 ) + name "F-Zero - Maximum Velocity (USA, Europe) (Virtual Console)" + description "F-Zero - Maximum Velocity (USA, Europe) (Virtual Console)" + rom ( name "F-Zero - Maximum Velocity (USA, Europe) (Virtual Console).gba" size 4194304 crc 4b5f1cdd sha1 bd08e426c743c7429efd576ce0ef00a70cffd72a flags verified ) ) game ( @@ -5737,9 +5965,9 @@ game ( ) game ( - name "F1 2002 (Europe) (En,Fr,De,Es,It)" - description "F1 2002 (Europe) (En,Fr,De,Es,It)" - rom ( name "F1 2002 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc aac551fd sha1 ae8c986de946e7fde8249e958c6743816fb05784 ) + name "F-Zero for Game Boy Advance (Japan)" + description "F-Zero for Game Boy Advance (Japan)" + rom ( name "F-Zero for Game Boy Advance (Japan).gba" size 4194304 crc 25e3fc9a sha1 cd8648b7158cf7c979cc05dea4c1aa927496e8b7 ) ) game ( @@ -5748,6 +5976,12 @@ game ( rom ( name "F1 2002 (USA, Europe).gba" size 4194304 crc 7dd20f33 sha1 c5b3860403425da6f062dd5b6d433781051e1a85 ) ) +game ( + name "F1 2002 (Europe) (En,Fr,De,Es,It)" + description "F1 2002 (Europe) (En,Fr,De,Es,It)" + rom ( name "F1 2002 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc aac551fd sha1 ae8c986de946e7fde8249e958c6743816fb05784 ) +) + game ( name "F24 Stealth Fighter (USA)" description "F24 Stealth Fighter (USA)" @@ -6030,6 +6264,12 @@ game ( rom ( name "Fanqiejiang Wangguo Da Maoxian (China) (Proto).gba" size 8388608 crc 5116a665 sha1 51ab57e6b414bae66f3e3ef4335dc0d68df2ed5e ) ) +game ( + name "Fantastic 4 (Europe)" + description "Fantastic 4 (Europe)" + rom ( name "Fantastic 4 (Europe).gba" size 16777216 crc b30ae33d sha1 758b2afaf4dcd96baab60e04d64eb22718efcecf ) +) + game ( name "Fantastic 4 (USA)" description "Fantastic 4 (USA)" @@ -6042,12 +6282,6 @@ game ( rom ( name "Fantastic 4 (Europe) (Fr,De,Es,Nl).gba" size 16777216 crc 88643de0 sha1 1e6ef7a4c941ea074ed88010f5cd7bab7c807d0d flags verified ) ) -game ( - name "Fantastic 4 (Europe)" - description "Fantastic 4 (Europe)" - rom ( name "Fantastic 4 (Europe).gba" size 16777216 crc b30ae33d sha1 758b2afaf4dcd96baab60e04d64eb22718efcecf ) -) - game ( name "Fantastic 4 - Flame On (USA)" description "Fantastic 4 - Flame On (USA)" @@ -6067,9 +6301,9 @@ game ( ) game ( - name "Fantastic Maerchen - Cake-ya-san Monogatari (Japan)" - description "Fantastic Maerchen - Cake-ya-san Monogatari (Japan)" - rom ( name "Fantastic Maerchen - Cake-ya-san Monogatari (Japan).gba" size 8388608 crc ec60d573 sha1 826c247ef4e5b831aa0d75e97cfdfe06c48ad7af ) + name "Fantastic Maerchen - Cake-ya-san Monogatari + Doubutsu Chara Navi Uranai - Kosei Shinri Gaku (Japan)" + description "Fantastic Maerchen - Cake-ya-san Monogatari + Doubutsu Chara Navi Uranai - Kosei Shinri Gaku (Japan)" + rom ( name "Fantastic Maerchen - Cake-ya-san Monogatari + Doubutsu Chara Navi Uranai - Kosei Shinri Gaku (Japan).gba" size 8388608 crc ec60d573 sha1 826c247ef4e5b831aa0d75e97cfdfe06c48ad7af ) ) game ( @@ -6085,9 +6319,9 @@ game ( ) game ( - name "Fear Factor Unleashed (USA)" - description "Fear Factor Unleashed (USA)" - rom ( name "Fear Factor Unleashed (USA).gba" size 8388608 crc 1289639c sha1 bf933c51bdcb52ae54d518e80129c687b751f836 ) + name "Fear Factor - Unleashed (USA)" + description "Fear Factor - Unleashed (USA)" + rom ( name "Fear Factor - Unleashed (USA).gba" size 8388608 crc 1289639c sha1 bf933c51bdcb52ae54d518e80129c687b751f836 ) ) game ( @@ -6324,6 +6558,12 @@ game ( rom ( name "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan).gba" size 16777216 crc a0093822 sha1 4894c960c64b4f2d250e054ffd5d6971940c3b17 ) ) +game ( + name "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan) (Rev 1)" + description "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan) (Rev 1)" + rom ( name "Final Fire Pro Wrestling - Yume no Dantai Unei! (Japan) (Rev 1).gba" size 16777216 crc 3f98600b sha1 2fbb9ef803a07c23139709179e6af25f141abe51 ) +) + game ( name "Findet Nemo (Germany) (Beta)" description "Findet Nemo (Germany) (Beta)" @@ -6345,7 +6585,7 @@ game ( game ( name "Finding Nemo (Japan)" description "Finding Nemo (Japan)" - rom ( name "Finding Nemo (Japan).gba" size 8388608 crc f895ba2d sha1 cab85c042c168e46ec42547a87af1b036e45c2a4 ) + rom ( name "Finding Nemo (Japan).gba" size 8388608 crc f895ba2d sha1 cab85c042c168e46ec42547a87af1b036e45c2a4 flags verified ) ) game ( @@ -6435,13 +6675,13 @@ game ( game ( name "Fire Emblem - Fuuin no Tsurugi (Japan)" description "Fire Emblem - Fuuin no Tsurugi (Japan)" - rom ( name "Fire Emblem - Fuuin no Tsurugi (Japan).gba" size 8388608 crc d38763e1 sha1 a57095da867de4d585c33d4394712986245fe6ca ) + rom ( name "Fire Emblem - Fuuin no Tsurugi (Japan).gba" size 8388608 crc d38763e1 sha1 a57095da867de4d585c33d4394712986245fe6ca flags verified ) ) game ( name "Fire Emblem - Rekka no Ken (Japan)" description "Fire Emblem - Rekka no Ken (Japan)" - rom ( name "Fire Emblem - Rekka no Ken (Japan).gba" size 16777216 crc f0c10e72 sha1 037702b1febd5c9535262165bf030551d153de81 ) + rom ( name "Fire Emblem - Rekka no Ken (Japan).gba" size 16777216 crc f0c10e72 sha1 037702b1febd5c9535262165bf030551d153de81 flags verified ) ) game ( @@ -6471,7 +6711,7 @@ game ( game ( name "Fire Emblem - Seima no Kouseki (Japan)" description "Fire Emblem - Seima no Kouseki (Japan)" - rom ( name "Fire Emblem - Seima no Kouseki (Japan).gba" size 16777216 crc 9d76826f sha1 7da0456035366aa18414faa79d8fe7649f03c1ed ) + rom ( name "Fire Emblem - Seima no Kouseki (Japan).gba" size 16777216 crc 9d76826f sha1 7da0456035366aa18414faa79d8fe7649f03c1ed flags verified ) ) game ( @@ -6972,6 +7212,18 @@ game ( rom ( name "Gauntlet - Dark Legacy (USA).gba" size 8388608 crc e99de964 sha1 3ea608f4ea2235886fa1d7256f6a9ae88c2c0e28 ) ) +game ( + name "GB-A TV Tuner PAL (China) (v1.3) (Unl)" + description "GB-A TV Tuner PAL (China) (v1.3) (Unl)" + rom ( name "GB-A TV Tuner PAL (China) (v1.3) (Unl).gba" size 524288 crc 63524b0f sha1 256f5510a2051ae0512c4e1e90b9a572b1d859b6 ) +) + +game ( + name "GB-A TV Tuner PAL (China) (v2.0) (Unl)" + description "GB-A TV Tuner PAL (China) (v2.0) (Unl)" + rom ( name "GB-A TV Tuner PAL (China) (v2.0) (Unl).gba" size 524288 crc 0abecb5b sha1 96425bba00c21cd5c1970d6d80de547a1e226338 ) +) + game ( name "GBA AV Adapter (China) (Unl)" description "GBA AV Adapter (China) (Unl)" @@ -6996,18 +7248,6 @@ game ( rom ( name "GBA Personal Organizer (USA) (Unl).gba" size 1048576 crc 424f71e5 sha1 26e7a5435372c46628985cba57f12a322b59537b ) ) -game ( - name "GBA TV Tuner PAL (China) (v1.3) (Unl)" - description "GBA TV Tuner PAL (China) (v1.3) (Unl)" - rom ( name "GBA TV Tuner PAL (China) (v1.3) (Unl).gba" size 1048576 crc af124f8c sha1 e0899f4097054862d33c03e21e9d4a5eef790402 ) -) - -game ( - name "GBA TV Tuner PAL (China) (v2.0) (Unl)" - description "GBA TV Tuner PAL (China) (v2.0) (Unl)" - rom ( name "GBA TV Tuner PAL (China) (v2.0) (Unl).gba" size 8388608 crc b511df64 sha1 5a62463cbaaa0c4586e227ad6ca6a5d54485d955 ) -) - game ( name "Gegege no Kitarou - Kikiippatsu! Youkai Rettou (Japan)" description "Gegege no Kitarou - Kikiippatsu! Youkai Rettou (Japan)" @@ -7110,6 +7350,12 @@ game ( rom ( name "Ghost Trap (Japan).gba" size 8388608 crc 81ea54e2 sha1 00efb5ed50127f91e2a2827926cf2d4491e4b1b3 ) ) +game ( + name "Glacia Dungeon (World) (En,Es,Ru,Ro) (v1.5.2) (Aftermarket) (Unl)" + description "Glacia Dungeon (World) (En,Es,Ru,Ro) (v1.5.2) (Aftermarket) (Unl)" + rom ( name "Glacia Dungeon (World) (En,Es,Ru,Ro) (v1.5.2) (Aftermarket) (Unl).gba" size 1210608 crc ab5ae65b sha1 e35037ff9cc24f8a7043d9a9d378e86d2ef80f9b ) +) + game ( name "Global Star - Sudoku Fever (USA)" description "Global Star - Sudoku Fever (USA)" @@ -7122,6 +7368,12 @@ game ( rom ( name "Global Star - Sudoku Fever (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 383cf600 sha1 8a6ab9e999cb9618bf169f70a9423abdc0de6a92 ) ) +game ( + name "Glucoboy (Australia)" + description "Glucoboy (Australia)" + rom ( name "Glucoboy (Australia).gba" size 16777216 crc 6e2d7eff sha1 4e9e198aef017bfe49802824e436ce47f2e807bb ) +) + game ( name "Go! Go! Beckham! - Adventure on Soccer Island (Europe) (En,Fr,De,Es,It)" description "Go! Go! Beckham! - Adventure on Soccer Island (Europe) (En,Fr,De,Es,It)" @@ -7167,7 +7419,7 @@ game ( game ( name "Golden Sun (France)" description "Golden Sun (France)" - rom ( name "Golden Sun (France).gba" size 8388608 crc f6521161 sha1 42f3b262c16cfc5bde1fa2b25016fb74046de1b3 ) + rom ( name "Golden Sun (France).gba" size 8388608 crc f6521161 sha1 42f3b262c16cfc5bde1fa2b25016fb74046de1b3 flags verified ) ) game ( @@ -7197,7 +7449,7 @@ game ( game ( name "Golden Sun - L'Age Perdu (France)" description "Golden Sun - L'Age Perdu (France)" - rom ( name "Golden Sun - L'Age Perdu (France).gba" size 16777216 crc 1090bd33 sha1 f14855c0f8c87a95cc52189e8e3b2bd9df186322 ) + rom ( name "Golden Sun - L'Age Perdu (France).gba" size 16777216 crc 1090bd33 sha1 f14855c0f8c87a95cc52189e8e3b2bd9df186322 flags verified ) ) game ( @@ -7225,45 +7477,93 @@ game ( ) game ( - name "Goodboy Galaxy (World) (En) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (En) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (En) (Demo) (Aftermarket) (Unl).gba" size 13224124 crc 19ba7d80 sha1 1bf95f8730ecdfa6665b85bea8764f42a88e8e3d ) + name "Goodboy Galaxy - Chapter Zero (World) (En) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (En) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (En) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13224124 crc 19ba7d80 sha1 1bf95f8730ecdfa6665b85bea8764f42a88e8e3d ) ) game ( - name "Goodboy Galaxy (World) (Ja) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (Ja) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (Ja) (Demo) (Aftermarket) (Unl).gba" size 13219728 crc d4621e3e sha1 5bd59fac58c5f9a375216e9d1cf85fa5262f21f7 ) + name "Goodboy Galaxy - Chapter Zero (World) (Ja) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Ja) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Ja) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13219728 crc d4621e3e sha1 5bd59fac58c5f9a375216e9d1cf85fa5262f21f7 ) ) game ( - name "Goodboy Galaxy (World) (Fr) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (Fr) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (Fr) (Demo) (Aftermarket) (Unl).gba" size 13225068 crc 21512022 sha1 8832d38f787f3e1da620fcae7514d7387445ccf2 ) + name "Goodboy Galaxy - Chapter Zero (World) (Fr) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Fr) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Fr) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13225068 crc 21512022 sha1 8832d38f787f3e1da620fcae7514d7387445ccf2 ) ) game ( - name "Goodboy Galaxy (World) (Es) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (Es) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (Es) (Demo) (Aftermarket) (Unl).gba" size 13223944 crc c1811c9b sha1 9d413bce82708df137215a2968306a5196b1638b ) + name "Goodboy Galaxy - Chapter Zero (World) (Es) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Es) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Es) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13223944 crc c1811c9b sha1 9d413bce82708df137215a2968306a5196b1638b ) ) game ( - name "Goodboy Galaxy (World) (Zh) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (Zh) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (Zh) (Demo) (Aftermarket) (Unl).gba" size 13269108 crc 3360e114 sha1 50186922ff77714b9ac638948b464cdbf80ab5fb ) + name "Goodboy Galaxy - Chapter Zero (World) (Zh) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Zh) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Zh) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13269108 crc 3360e114 sha1 50186922ff77714b9ac638948b464cdbf80ab5fb ) ) game ( - name "Goodboy Galaxy (World) (Pt) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (Pt) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (Pt) (Demo) (Aftermarket) (Unl).gba" size 13223696 crc 3477ef15 sha1 4b447de09a23fbfdaa6d640824f8ceb5bbe56fab ) + name "Goodboy Galaxy - Chapter Zero (World) (Pt) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Pt) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Pt) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13223696 crc 3477ef15 sha1 4b447de09a23fbfdaa6d640824f8ceb5bbe56fab ) ) game ( - name "Goodboy Galaxy (World) (Ar) (Demo) (Aftermarket) (Unl)" - description "Goodboy Galaxy (World) (Ar) (Demo) (Aftermarket) (Unl)" - rom ( name "Goodboy Galaxy (World) (Ar) (Demo) (Aftermarket) (Unl).gba" size 13250016 crc a4054c2b sha1 c3cd833b9bdf87a8481c9b05251bba782bc3527e ) + name "Goodboy Galaxy - Chapter Zero (World) (Ar) (v1.0.6) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Ar) (v1.0.6) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Ar) (v1.0.6) (Demo) (Aftermarket) (Unl).gba" size 13250016 crc a4054c2b sha1 c3cd833b9bdf87a8481c9b05251bba782bc3527e ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (En) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (En) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (En) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13220676 crc ab179d6e sha1 2ad1c4840f2f6c2138ed44b1a7aa36071c227a0a ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (Fr) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Fr) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Fr) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13221620 crc 3aa591f1 sha1 2548615eeaecd7498e32d02b5c758b713ada27f4 ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (De) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (De) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (De) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13221368 crc d02cdb6a sha1 1e579e15bdc8dc1def99bcb3c30acfc185e0476b ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (Es) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Es) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Es) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13220496 crc 906717a5 sha1 31857a9ab4daa537322f80faa77482a4b8120483 ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (Pt) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Pt) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Pt) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13220252 crc d12372bd sha1 89ea5ea41133419c317fd28e7c7f172f5bb53ec3 ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (Ja) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Ja) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Ja) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13216280 crc d3c8dffd sha1 c41c0596a4c52b0e26bb9ffe5c9f7f1c064e0be6 ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (Zh) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Zh) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Zh) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13265660 crc 119f9ddc sha1 d6c23ff47b21a7bf2f8238ac916aeea3866042b5 ) +) + +game ( + name "Goodboy Galaxy - Chapter Zero (World) (Ar) (v1.0.7) (Demo) (Aftermarket) (Unl)" + description "Goodboy Galaxy - Chapter Zero (World) (Ar) (v1.0.7) (Demo) (Aftermarket) (Unl)" + rom ( name "Goodboy Galaxy - Chapter Zero (World) (Ar) (v1.0.7) (Demo) (Aftermarket) (Unl).gba" size 13246576 crc b14cd1b4 sha1 0d15bd0584148b1658f7d47a2dda604a936ea166 ) ) game ( @@ -7314,6 +7614,18 @@ game ( rom ( name "Green Eggs and Ham by Dr. Seuss (USA).gba" size 4194304 crc e4ae2cd1 sha1 be062fa28db26ec37ec96e5a7e6dc77cf4ad6907 ) ) +game ( + name "Green Memories (World) (v1.2.0) (Aftermarket) (Unl)" + description "Green Memories (World) (v1.2.0) (Aftermarket) (Unl)" + rom ( name "Green Memories (World) (v1.2.0) (Aftermarket) (Unl).gba" size 6639328 crc 78b81bbc sha1 fb090890bd767a22afe07b3323dd0992d698c906 ) +) + +game ( + name "Green Memories (World) (v1.4.2) (Aftermarket) (Unl)" + description "Green Memories (World) (v1.4.2) (Aftermarket) (Unl)" + rom ( name "Green Memories (World) (v1.4.2) (Aftermarket) (Unl).gba" size 6937384 crc 9fa9f00f sha1 005f4dc0d615d36d32bbe36e9cc9007b22be2ecd ) +) + game ( name "Greg Hastings' Tournament Paintball Max'd (USA)" description "Greg Hastings' Tournament Paintball Max'd (USA)" @@ -7326,18 +7638,18 @@ game ( rom ( name "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt) (Beta).gba" size 4194304 crc 68ae6bbb sha1 6aa43d0624af03214473f329fda6334dc9c63009 ) ) -game ( - name "Gremlins - Stripe vs Gizmo (USA)" - description "Gremlins - Stripe vs Gizmo (USA)" - rom ( name "Gremlins - Stripe vs Gizmo (USA).gba" size 4194304 crc 5e72899a sha1 ee32e704598d2b6a21b3db271f9cf94578b94744 ) -) - game ( name "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt)" description "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt)" rom ( name "Gremlins - Stripe vs Gizmo (Europe) (En,Fr,De,Es,It,Pt).gba" size 4194304 crc b6225186 sha1 a2c4bf97785e717ef45e4b73a6c66a2d4ae18192 ) ) +game ( + name "Gremlins - Stripe vs Gizmo (USA)" + description "Gremlins - Stripe vs Gizmo (USA)" + rom ( name "Gremlins - Stripe vs Gizmo (USA).gba" size 4194304 crc 5e72899a sha1 ee32e704598d2b6a21b3db271f9cf94578b94744 ) +) + game ( name "Grim Adventures of Billy & Mandy, The (USA)" description "Grim Adventures of Billy & Mandy, The (USA)" @@ -7417,15 +7729,9 @@ game ( ) game ( - name "Guilty Gear X - Advance Edition (Japan)" - description "Guilty Gear X - Advance Edition (Japan)" - rom ( name "Guilty Gear X - Advance Edition (Japan).gba" size 8388608 crc 160903ee sha1 0801b7e39462527d5b650e57fcce908711258a0c ) -) - -game ( - name "Guilty Gear X - Advance Edition (Europe)" - description "Guilty Gear X - Advance Edition (Europe)" - rom ( name "Guilty Gear X - Advance Edition (Europe).gba" size 8388608 crc ba95861d sha1 8236a650a18dfedc22da7c00b5affd3e752ec5de ) + name "Guilty Gear X - Advance Edition (Japan) (Beta)" + description "Guilty Gear X - Advance Edition (Japan) (Beta)" + rom ( name "Guilty Gear X - Advance Edition (Japan) (Beta).gba" size 8388608 crc 4506ada8 sha1 85915ecf10ce73afe9fffbbc8cd7a449dfe802c4 ) ) game ( @@ -7435,9 +7741,15 @@ game ( ) game ( - name "Guilty Gear X - Advance Edition (Japan) (Beta)" - description "Guilty Gear X - Advance Edition (Japan) (Beta)" - rom ( name "Guilty Gear X - Advance Edition (Japan) (Beta).gba" size 8388608 crc 4506ada8 sha1 85915ecf10ce73afe9fffbbc8cd7a449dfe802c4 ) + name "Guilty Gear X - Advance Edition (Japan)" + description "Guilty Gear X - Advance Edition (Japan)" + rom ( name "Guilty Gear X - Advance Edition (Japan).gba" size 8388608 crc 160903ee sha1 0801b7e39462527d5b650e57fcce908711258a0c ) +) + +game ( + name "Guilty Gear X - Advance Edition (Europe)" + description "Guilty Gear X - Advance Edition (Europe)" + rom ( name "Guilty Gear X - Advance Edition (Europe).gba" size 8388608 crc ba95861d sha1 8236a650a18dfedc22da7c00b5affd3e752ec5de ) ) game ( @@ -7530,12 +7842,6 @@ game ( rom ( name "Gyakuten Saiban 3 (Japan).gba" size 8388608 crc 51b6cf22 sha1 70944b396da3f9ce039cc96bc1661826c37b0aa2 flags verified ) ) -game ( - name "Ha Li Bo Te IV (Taiwan) (Unl)" - description "Ha Li Bo Te IV (Taiwan) (Unl)" - rom ( name "Ha Li Bo Te IV (Taiwan) (Unl).gba" size 33554432 crc 892347d4 sha1 80c0a695e23fa5d867da0e39203a52adaab2601d ) -) - game ( name "Hachiemon (Japan)" description "Hachiemon (Japan)" @@ -7560,6 +7866,12 @@ game ( rom ( name "Hajime no Ippo - The Fighting! (Japan).gba" size 8388608 crc 782dc7eb sha1 4b39dde92aa2e26433a9f0c90ca6235a508ba87c ) ) +game ( + name "Hali Bote IV (Taiwan) (Unl)" + description "Hali Bote IV (Taiwan) (Unl)" + rom ( name "Hali Bote IV (Taiwan) (Unl).gba" size 33554432 crc 892347d4 sha1 80c0a695e23fa5d867da0e39203a52adaab2601d ) +) + game ( name "Hamepane - Tokyo Mew Mew (Japan)" description "Hamepane - Tokyo Mew Mew (Japan)" @@ -7629,7 +7941,7 @@ game ( game ( name "Hamtaro - Ham-Ham Heartbreak (Europe) (En,Fr,De,Es,It)" description "Hamtaro - Ham-Ham Heartbreak (Europe) (En,Fr,De,Es,It)" - rom ( name "Hamtaro - Ham-Ham Heartbreak (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc ecbd80ea sha1 b016328e4880f0413b9335c95758ba9c09e53710 ) + rom ( name "Hamtaro - Ham-Ham Heartbreak (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc ecbd80ea sha1 b016328e4880f0413b9335c95758ba9c09e53710 flags verified ) ) game ( @@ -7644,6 +7956,12 @@ game ( rom ( name "Hamtaro - Rainbow Rescue (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 5d051081 sha1 b6446397744c10eb08f112f005e995dd9954a675 ) ) +game ( + name "Hamtaro - Rainbow Rescue (USA) (Proto) (2003-07-29)" + description "Hamtaro - Rainbow Rescue (USA) (Proto) (2003-07-29)" + rom ( name "Hamtaro - Rainbow Rescue (USA) (Proto) (2003-07-29).gba" size 16777216 crc fd630f6c sha1 14cf38e86f019572393f0109680ff2db345f9f50 ) +) + game ( name "Hanabi Hyakkei Advance (Japan)" description "Hanabi Hyakkei Advance (Japan)" @@ -7944,18 +8262,18 @@ game ( rom ( name "Hikaru no Go (Japan) (Rev 1).gba" size 8388608 crc 53116fd7 sha1 c61227f6ccfdc196ef810c1986322b0b1988e508 ) ) -game ( - name "Hikaru no Go (Japan) (Demo) (Promo)" - description "Hikaru no Go (Japan) (Demo) (Promo)" - rom ( name "Hikaru no Go (Japan) (Demo) (Promo).gba" size 4194304 crc 4955fa1b sha1 636c3247f455263c41fc0dee85fd4532246b60c2 ) -) - game ( name "Hikaru no Go (Japan)" description "Hikaru no Go (Japan)" rom ( name "Hikaru no Go (Japan).gba" size 8388608 crc 5a6c7537 sha1 a96299f55026b959ed806bff0fb4a440d33e65af ) ) +game ( + name "Hikaru no Go - Taikenban (Japan) (Demo)" + description "Hikaru no Go - Taikenban (Japan) (Demo)" + rom ( name "Hikaru no Go - Taikenban (Japan) (Demo).gba" size 4194304 crc 4955fa1b sha1 636c3247f455263c41fc0dee85fd4532246b60c2 ) +) + game ( name "Hikaru no Go 2 (Japan)" description "Hikaru no Go 2 (Japan)" @@ -7963,9 +8281,9 @@ game ( ) game ( - name "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan)" - description "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan)" - rom ( name "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan).gba" size 8388608 crc 8ea9afcc sha1 fefc7a73ddceaf28ebb95b88f5f39a5489024d4e ) + name "Hikaru no Go 3 - Senyou Joy Carry Cartridge (Japan) (Rewritable Cartridge)" + description "Hikaru no Go 3 - Senyou Joy Carry Cartridge (Japan) (Rewritable Cartridge)" + rom ( name "Hikaru no Go 3 - Senyou Joy Carry Cartridge (Japan) (Rewritable Cartridge).gba" size 33554432 crc 5bfbc276 sha1 e064ceecae66f7eb0b6ba4f19424a52e504f4bf2 ) ) game ( @@ -7974,6 +8292,12 @@ game ( rom ( name "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan) (Rev 1).gba" size 8388608 crc 526fdfff sha1 93b98fcf585483722240e56c01826ae5c31930e4 ) ) +game ( + name "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan)" + description "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan)" + rom ( name "Himawari Doubutsu Byouin - Pet no Oishasan Ikusei Game (Japan).gba" size 8388608 crc 8ea9afcc sha1 fefc7a73ddceaf28ebb95b88f5f39a5489024d4e ) +) + game ( name "Hime Kishi Monogatari - Princess Blue (Japan)" description "Hime Kishi Monogatari - Princess Blue (Japan)" @@ -8004,6 +8328,12 @@ game ( rom ( name "Hobbit, The - The Prelude to the Lord of the Rings (USA).gba" size 8388608 crc d3f654b3 sha1 70d04d6d3ab8a1bfc4fa1a26d55cd4f73f84d479 ) ) +game ( + name "Holy Bible, The - World English Bible (USA) (Proto)" + description "Holy Bible, The - World English Bible (USA) (Proto)" + rom ( name "Holy Bible, The - World English Bible (USA) (Proto).gba" size 4194304 crc 0152a619 sha1 807d0b3dcf5ea7e972a0ecf0cecb03a040befb91 ) +) + game ( name "Home on the Range (USA) (En,Fr)" description "Home on the Range (USA) (En,Fr)" @@ -8035,9 +8365,9 @@ game ( ) game ( - name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Virtual Console)" - description "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Virtual Console)" - rom ( name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Virtual Console).gba" size 16777216 crc 3da3603b sha1 700006a8b919d7ee4b7dd972dbf6c429d1adca71 ) + name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Rev 1) (Virtual Console)" + description "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Rev 1) (Virtual Console)" + rom ( name "Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (Rev 1) (Virtual Console).gba" size 16777216 crc 3da3603b sha1 700006a8b919d7ee4b7dd972dbf6c429d1adca71 ) ) game ( @@ -8055,7 +8385,7 @@ game ( game ( name "Hot Potato! (USA)" description "Hot Potato! (USA)" - rom ( name "Hot Potato! (USA).gba" size 4194304 crc 5acb7a95 sha1 6d07c27f7d7858f177cf3c1466ea5a8858df4f92 ) + rom ( name "Hot Potato! (USA).gba" size 4194304 crc 5acb7a95 sha1 6d07c27f7d7858f177cf3c1466ea5a8858df4f92 flags verified ) ) game ( @@ -8262,6 +8592,18 @@ game ( rom ( name "Ignition Collection - Volume 1 (Europe).gba" size 16777216 crc 164a75ac sha1 62e598f9c6ea47626954619295107955ad7c371a ) ) +game ( + name "IK+ (USA)" + description "IK+ (USA)" + rom ( name "IK+ (USA).gba" size 4194304 crc 31c4f03b sha1 99075504699400430e9817feb4192a6e153fbc9a ) +) + +game ( + name "IK+ (Europe)" + description "IK+ (Europe)" + rom ( name "IK+ (Europe).gba" size 4194304 crc 1052a0ea sha1 844395914641af431c58bbe82ab2513c5f8a60ce ) +) + game ( name "Incredibili, Gli - Una 'Normale' Famiglia di Supereroi (Italy)" description "Incredibili, Gli - Una 'Normale' Famiglia di Supereroi (Italy)" @@ -8310,12 +8652,30 @@ game ( rom ( name "Increibles, Los (Spain).gba" size 8388608 crc fc6ccadb sha1 c87047934ae328f52ef6b01083a57c65cbbab514 ) ) +game ( + name "Inheritors of the Oubliette (World) (v1.2) (Aftermarket) (Unl)" + description "Inheritors of the Oubliette (World) (v1.2) (Aftermarket) (Unl)" + rom ( name "Inheritors of the Oubliette (World) (v1.2) (Aftermarket) (Unl).gba" size 10592124 crc a9014760 sha1 2430c6c0784912ad2f0b51e633bf577f087f189f ) +) + +game ( + name "Inheritors of the Oubliette (World) (GBA Jam) (Aftermarket) (Unl)" + description "Inheritors of the Oubliette (World) (GBA Jam) (Aftermarket) (Unl)" + rom ( name "Inheritors of the Oubliette (World) (GBA Jam) (Aftermarket) (Unl).gba" size 25516708 crc 965a1a75 sha1 ae23cfba1f53a9bbde025490f3d7bdf52c3970e4 ) +) + game ( name "Initial D - Another Stage (Japan)" description "Initial D - Another Stage (Japan)" rom ( name "Initial D - Another Stage (Japan).gba" size 8388608 crc 23110a94 sha1 abc8a136e00e38132bf07d38cf28e52a2719fab9 ) ) +game ( + name "Inky and the Alien Aquarium (World) (Demo) (Aftermarket) (Unl)" + description "Inky and the Alien Aquarium (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Inky and the Alien Aquarium (World) (Demo) (Aftermarket) (Unl).gba" size 3145728 crc 7ee7ae7f sha1 73d870fad3caa86b6f659e13b57eddac80db2f37 ) +) + game ( name "Inspector Gadget - Advance Mission (Europe) (En,Fr,De,Es,It,Nl)" description "Inspector Gadget - Advance Mission (Europe) (En,Fr,De,Es,It,Nl)" @@ -8340,18 +8700,6 @@ game ( rom ( name "International Karate Advanced (Europe).gba" size 4194304 crc d33a14af sha1 bb8b12d0a446ed097fb74a9a4496980fb65164ef flags verified ) ) -game ( - name "International Karate Plus (Europe)" - description "International Karate Plus (Europe)" - rom ( name "International Karate Plus (Europe).gba" size 4194304 crc 1052a0ea sha1 844395914641af431c58bbe82ab2513c5f8a60ce ) -) - -game ( - name "International Karate Plus (USA)" - description "International Karate Plus (USA)" - rom ( name "International Karate Plus (USA).gba" size 4194304 crc 31c4f03b sha1 99075504699400430e9817feb4192a6e153fbc9a ) -) - game ( name "International Superstar Soccer (Europe)" description "International Superstar Soccer (Europe)" @@ -8401,9 +8749,9 @@ game ( ) game ( - name "Iridion 3D (World) (Aftermarket) (Unl)" - description "Iridion 3D (World) (Aftermarket) (Unl)" - rom ( name "Iridion 3D (World) (Aftermarket) (Unl).gba" size 4194304 crc 4c7ebe42 sha1 6f1c77ab88351d2d50da412e4788fc7ca8a6714d ) + name "Iridion 3D (USA) (Aftermarket) (Unl)" + description "Iridion 3D (USA) (Aftermarket) (Unl)" + rom ( name "Iridion 3D (USA) (Aftermarket) (Unl).gba" size 4194304 crc 4c7ebe42 sha1 6f1c77ab88351d2d50da412e4788fc7ca8a6714d ) ) game ( @@ -8421,7 +8769,7 @@ game ( game ( name "Iridion II (Europe) (En,Fr,De)" description "Iridion II (Europe) (En,Fr,De)" - rom ( name "Iridion II (Europe) (En,Fr,De).gba" size 8388608 crc 57930c6a sha1 661442c24404cc0727e4343f9ce570c87c797661 ) + rom ( name "Iridion II (Europe) (En,Fr,De).gba" size 8388608 crc 57930c6a sha1 661442c24404cc0727e4343f9ce570c87c797661 flags verified ) ) game ( @@ -8431,9 +8779,9 @@ game ( ) game ( - name "Iridion II (World) (Aftermarket) (Unl)" - description "Iridion II (World) (Aftermarket) (Unl)" - rom ( name "Iridion II (World) (Aftermarket) (Unl).gba" size 8388608 crc b371f070 sha1 cc788b38a047ff5ec8c445ce11efcd1852ad7c4d ) + name "Iridion II (USA) (Aftermarket) (Unl)" + description "Iridion II (USA) (Aftermarket) (Unl)" + rom ( name "Iridion II (USA) (Aftermarket) (Unl).gba" size 8388608 crc b371f070 sha1 cc788b38a047ff5ec8c445ce11efcd1852ad7c4d ) ) game ( @@ -8460,18 +8808,18 @@ game ( rom ( name "It's Mr. Pants (USA, Europe).gba" size 4194304 crc 757a4efb sha1 c49742f964a698ccce0520e24368a9d425a29b4d flags verified ) ) -game ( - name "J.League Pocket (Japan)" - description "J.League Pocket (Japan)" - rom ( name "J.League Pocket (Japan).gba" size 8388608 crc 51be73b8 sha1 b4cd024b10d740f3525dddfbcc613c04a8d4c166 ) -) - game ( name "J.League Pocket (Japan) (Rev 1)" description "J.League Pocket (Japan) (Rev 1)" rom ( name "J.League Pocket (Japan) (Rev 1).gba" size 8388608 crc 0524e9ef sha1 64c6b3f0113d91daf41e63b2755d26b9ed0cea3a ) ) +game ( + name "J.League Pocket (Japan)" + description "J.League Pocket (Japan)" + rom ( name "J.League Pocket (Japan).gba" size 8388608 crc 51be73b8 sha1 b4cd024b10d740f3525dddfbcc613c04a8d4c166 ) +) + game ( name "J.League Pocket 2 (Japan)" description "J.League Pocket 2 (Japan)" @@ -8544,12 +8892,6 @@ game ( rom ( name "JGTO Kounin Golf Master Mobile - Japan Golf Tour Game (Japan).gba" size 8388608 crc b863dae1 sha1 975cff59783cd8f5ec30caaa9e6bef130a6e3529 ) ) -game ( - name "Ji Xie Ren Da Zhan - Zhong Jie Ban (Taiwan) (Unl)" - description "Ji Xie Ren Da Zhan - Zhong Jie Ban (Taiwan) (Unl)" - rom ( name "Ji Xie Ren Da Zhan - Zhong Jie Ban (Taiwan) (Unl).gba" size 8388608 crc 81462aba sha1 75e94c4b91638dcb82a6a6778394ec8dc7940091 ) -) - game ( name "Jikkyou World Soccer Pocket (Japan)" description "Jikkyou World Soccer Pocket (Japan)" @@ -8563,15 +8905,15 @@ game ( ) game ( - name "Jimmy Neutron Boy Genius (USA)" - description "Jimmy Neutron Boy Genius (USA)" - rom ( name "Jimmy Neutron Boy Genius (USA).gba" size 4194304 crc d3ee0c51 sha1 31ed7659e2e072d1c00baf95c0ee9c770e949900 ) + name "Jimmy Neutron - Boy Genius (USA)" + description "Jimmy Neutron - Boy Genius (USA)" + rom ( name "Jimmy Neutron - Boy Genius (USA).gba" size 4194304 crc d3ee0c51 sha1 31ed7659e2e072d1c00baf95c0ee9c770e949900 ) ) game ( - name "Jimmy Neutron Boy Genius (Europe) (En,Fr,De,Es)" - description "Jimmy Neutron Boy Genius (Europe) (En,Fr,De,Es)" - rom ( name "Jimmy Neutron Boy Genius (Europe) (En,Fr,De,Es).gba" size 4194304 crc a9423234 sha1 0923b6186739ba697627822ebce04edaa721a70f ) + name "Jimmy Neutron - Boy Genius (Europe) (En,Fr,De,Es)" + description "Jimmy Neutron - Boy Genius (Europe) (En,Fr,De,Es)" + rom ( name "Jimmy Neutron - Boy Genius (Europe) (En,Fr,De,Es).gba" size 4194304 crc a9423234 sha1 0923b6186739ba697627822ebce04edaa721a70f ) ) game ( @@ -8604,6 +8946,12 @@ game ( rom ( name "Jisu F-Zero Weilai Saiche (China).gba" size 4194304 crc 0e5c38b7 sha1 2bf6622398655a16a5d6b3d94241b72e63a71de9 ) ) +game ( + name "Jixie Ren Dazhan - Zhongjie Ban (Taiwan) (Unl)" + description "Jixie Ren Dazhan - Zhongjie Ban (Taiwan) (Unl)" + rom ( name "Jixie Ren Dazhan - Zhongjie Ban (Taiwan) (Unl).gba" size 8388608 crc 81462aba sha1 75e94c4b91638dcb82a6a6778394ec8dc7940091 ) +) + game ( name "Jonny Moseley Mad Trix (USA, Europe) (En,Fr,De,Es,It)" description "Jonny Moseley Mad Trix (USA, Europe) (En,Fr,De,Es,It)" @@ -8631,7 +8979,7 @@ game ( game ( name "Jungle Book 2, The (Europe) (En,Fr,De,Es,It,Nl)" description "Jungle Book 2, The (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Jungle Book 2, The (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 9898258b sha1 4dd4fbf9ecd755c37dfb5f6eb0094873c72aabc2 ) + rom ( name "Jungle Book 2, The (Europe) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 9898258b sha1 4dd4fbf9ecd755c37dfb5f6eb0094873c72aabc2 flags verified ) ) game ( @@ -8712,18 +9060,18 @@ game ( rom ( name "Justice League - Injustice for All (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc d71c4382 sha1 7385169111585230ba62007397802a7197653447 ) ) -game ( - name "Justice League - Injustice for All (USA) (Beta)" - description "Justice League - Injustice for All (USA) (Beta)" - rom ( name "Justice League - Injustice for All (USA) (Beta).gba" size 8388608 crc c41081cf sha1 e3302c2aa5cd14bf5546a3069bc6757363ee38b4 ) -) - game ( name "Justice League - Injustice for All (USA)" description "Justice League - Injustice for All (USA)" rom ( name "Justice League - Injustice for All (USA).gba" size 8388608 crc b2477b72 sha1 f7d774f3d1f1436c18b044c65e574dc327ad6437 ) ) +game ( + name "Justice League - Injustice for All (USA) (Beta)" + description "Justice League - Injustice for All (USA) (Beta)" + rom ( name "Justice League - Injustice for All (USA) (Beta).gba" size 8388608 crc c41081cf sha1 e3302c2aa5cd14bf5546a3069bc6757363ee38b4 ) +) + game ( name "Justice League Heroes - The Flash (USA)" description "Justice League Heroes - The Flash (USA)" @@ -8779,15 +9127,15 @@ game ( ) game ( - name "Kao the Kangaroo (USA) (En,Fr,De,Es,It,Nl)" - description "Kao the Kangaroo (USA) (En,Fr,De,Es,It,Nl)" - rom ( name "Kao the Kangaroo (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc f6667b3e sha1 772d323145cb7707cb8792bdfd5c7ef5e1e27c46 ) + name "KAO the Kangaroo (USA) (En,Fr,De,Es,It,Nl)" + description "KAO the Kangaroo (USA) (En,Fr,De,Es,It,Nl)" + rom ( name "KAO the Kangaroo (USA) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc f6667b3e sha1 772d323145cb7707cb8792bdfd5c7ef5e1e27c46 ) ) game ( - name "Kao the Kangaroo (Europe) (En,Fr,De,Es,It,Nl)" - description "Kao the Kangaroo (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Kao the Kangaroo (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 51e7522c sha1 5a337fcc321eaa0c350644c026767824add338f3 ) + name "KAO the Kangaroo (Europe) (En,Fr,De,Es,It,Nl)" + description "KAO the Kangaroo (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "KAO the Kangaroo (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 51e7522c sha1 5a337fcc321eaa0c350644c026767824add338f3 ) ) game ( @@ -8799,7 +9147,7 @@ game ( game ( name "Karnaaj Rally (USA, Europe)" description "Karnaaj Rally (USA, Europe)" - rom ( name "Karnaaj Rally (USA, Europe).gba" size 8388608 crc 63fe3dfe sha1 31bb73186bb98f3d2b80089490f2eeca2861fe5e ) + rom ( name "Karnaaj Rally (USA, Europe).gba" size 8388608 crc 63fe3dfe sha1 31bb73186bb98f3d2b80089490f2eeca2861fe5e flags verified ) ) game ( @@ -8877,7 +9225,7 @@ game ( game ( name "Kelly Slater's Pro Surfer (USA, Europe)" description "Kelly Slater's Pro Surfer (USA, Europe)" - rom ( name "Kelly Slater's Pro Surfer (USA, Europe).gba" size 8388608 crc 31f85dbe sha1 73328bfd274d1ec77c9a67351c026e22f09eeff5 ) + rom ( name "Kelly Slater's Pro Surfer (USA, Europe).gba" size 8388608 crc 31f85dbe sha1 73328bfd274d1ec77c9a67351c026e22f09eeff5 flags verified ) ) game ( @@ -9012,18 +9360,18 @@ game ( rom ( name "Kim Possible - Revenge of Monkey Fist (USA).gba" size 8388608 crc 1a56efbd sha1 64ef958beae876d3a6c295d0351d671b6991774b ) ) -game ( - name "Kim Possible 2 - Drakken's Demise (USA) (En,Fr)" - description "Kim Possible 2 - Drakken's Demise (USA) (En,Fr)" - rom ( name "Kim Possible 2 - Drakken's Demise (USA) (En,Fr).gba" size 8388608 crc fa946fc6 sha1 d2baaec3c20b48bebe79ebe27761cd107fd067bf flags verified ) -) - game ( name "Kim Possible 2 - Drakken's Demise (Europe) (En,Fr,De,Es)" description "Kim Possible 2 - Drakken's Demise (Europe) (En,Fr,De,Es)" rom ( name "Kim Possible 2 - Drakken's Demise (Europe) (En,Fr,De,Es).gba" size 8388608 crc 71c505c8 sha1 eb4099911dbd28073c554f4d4fa35cbeed82bc6b ) ) +game ( + name "Kim Possible 2 - Drakken's Demise (USA) (En,Fr)" + description "Kim Possible 2 - Drakken's Demise (USA) (En,Fr)" + rom ( name "Kim Possible 2 - Drakken's Demise (USA) (En,Fr).gba" size 8388608 crc fa946fc6 sha1 d2baaec3c20b48bebe79ebe27761cd107fd067bf flags verified ) +) + game ( name "Kim Possible 3 - Team Possible (USA) (En,Fr)" description "Kim Possible 3 - Team Possible (USA) (En,Fr)" @@ -9048,12 +9396,6 @@ game ( rom ( name "King of Fighters EX 2, The - Howling Blood (USA) (Beta) (2003-04-03).gba" size 8388608 crc 7704ff39 sha1 b859122c1813a5ec9fb565dcca815a9f0a52bf18 ) ) -game ( - name "King of Fighters EX 2, The - Howling Blood (Japan) (Rev 1)" - description "King of Fighters EX 2, The - Howling Blood (Japan) (Rev 1)" - rom ( name "King of Fighters EX 2, The - Howling Blood (Japan) (Rev 1).gba" size 8388608 crc dc5beacd sha1 2b7ec55de56d7f7f0932a53a0d3fcc3f36a0af8e ) -) - game ( name "King of Fighters EX 2, The - Howling Blood (Europe)" description "King of Fighters EX 2, The - Howling Blood (Europe)" @@ -9067,15 +9409,9 @@ game ( ) game ( - name "King of Fighters EX, The - NeoBlood (USA) (Rev 1)" - description "King of Fighters EX, The - NeoBlood (USA) (Rev 1)" - rom ( name "King of Fighters EX, The - NeoBlood (USA) (Rev 1).gba" size 8388608 crc 0f960e70 sha1 3031264c4b27cac55c2df38ab5f2bfcafa7c301d ) -) - -game ( - name "King of Fighters EX, The - NeoBlood (Japan) (Beta)" - description "King of Fighters EX, The - NeoBlood (Japan) (Beta)" - rom ( name "King of Fighters EX, The - NeoBlood (Japan) (Beta).gba" size 8388608 crc 811ffcfa sha1 cde8454951d3509f0b2bf9de98221eef248f5f8d ) + name "King of Fighters EX 2, The - Howling Blood (Japan) (Rev 1)" + description "King of Fighters EX 2, The - Howling Blood (Japan) (Rev 1)" + rom ( name "King of Fighters EX 2, The - Howling Blood (Japan) (Rev 1).gba" size 8388608 crc dc5beacd sha1 2b7ec55de56d7f7f0932a53a0d3fcc3f36a0af8e ) ) game ( @@ -9096,6 +9432,18 @@ game ( rom ( name "King of Fighters EX, The - NeoBlood (Europe).gba" size 8388608 crc 17e66b52 sha1 48c85734164d4d83a232b5aca6bb9a2c5b7f5317 ) ) +game ( + name "King of Fighters EX, The - NeoBlood (USA) (Rev 1)" + description "King of Fighters EX, The - NeoBlood (USA) (Rev 1)" + rom ( name "King of Fighters EX, The - NeoBlood (USA) (Rev 1).gba" size 8388608 crc 0f960e70 sha1 3031264c4b27cac55c2df38ab5f2bfcafa7c301d ) +) + +game ( + name "King of Fighters EX, The - NeoBlood (Japan) (Beta)" + description "King of Fighters EX, The - NeoBlood (Japan) (Beta)" + rom ( name "King of Fighters EX, The - NeoBlood (Japan) (Beta).gba" size 8388608 crc 811ffcfa sha1 cde8454951d3509f0b2bf9de98221eef248f5f8d ) +) + game ( name "Kingdom Hearts - Chain of Memories (Japan)" description "Kingdom Hearts - Chain of Memories (Japan)" @@ -9139,9 +9487,9 @@ game ( ) game ( - name "Kirby - Nightmare in Dream Land (Europe) (En,Fr,De,Es,It)" - description "Kirby - Nightmare in Dream Land (Europe) (En,Fr,De,Es,It)" - rom ( name "Kirby - Nightmare in Dream Land (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 3b7a7477 sha1 39b00beee4558e6738859cfa250e4e0fcaae626e flags verified ) + name "Kirby - Nightmare in Dream Land (USA) (Virtual Console)" + description "Kirby - Nightmare in Dream Land (USA) (Virtual Console)" + rom ( name "Kirby - Nightmare in Dream Land (USA) (Virtual Console).gba" size 8388608 crc 1af07ac8 sha1 3d142008d50a64c315fd2d7cbd86ba94dffa2e12 ) ) game ( @@ -9151,15 +9499,9 @@ game ( ) game ( - name "Kirby - Nightmare in Dream Land (USA) (Virtual Console)" - description "Kirby - Nightmare in Dream Land (USA) (Virtual Console)" - rom ( name "Kirby - Nightmare in Dream Land (USA) (Virtual Console).gba" size 8388608 crc 1af07ac8 sha1 3d142008d50a64c315fd2d7cbd86ba94dffa2e12 ) -) - -game ( - name "Kirby & The Amazing Mirror (USA) (Virtual Console)" - description "Kirby & The Amazing Mirror (USA) (Virtual Console)" - rom ( name "Kirby & The Amazing Mirror (USA) (Virtual Console).gba" size 16777216 crc f70ebb99 sha1 a7b758c2abf4f0ef722922eab4d394a1579b52e8 ) + name "Kirby - Nightmare in Dream Land (Europe) (En,Fr,De,Es,It)" + description "Kirby - Nightmare in Dream Land (Europe) (En,Fr,De,Es,It)" + rom ( name "Kirby - Nightmare in Dream Land (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 3b7a7477 sha1 39b00beee4558e6738859cfa250e4e0fcaae626e flags verified ) ) game ( @@ -9174,6 +9516,12 @@ game ( rom ( name "Kirby & The Amazing Mirror (USA).gba" size 16777216 crc 9f2a3048 sha1 274b102b6d940f46861a92b4e65f89a51815c12c flags verified ) ) +game ( + name "Kirby & The Amazing Mirror (USA) (Virtual Console)" + description "Kirby & The Amazing Mirror (USA) (Virtual Console)" + rom ( name "Kirby & The Amazing Mirror (USA) (Virtual Console).gba" size 16777216 crc f70ebb99 sha1 a7b758c2abf4f0ef722922eab4d394a1579b52e8 ) +) + game ( name "Kirby & The Amazing Mirror (Europe) (En,Fr,De,Es,It) (Virtual Console)" description "Kirby & The Amazing Mirror (Europe) (En,Fr,De,Es,It) (Virtual Console)" @@ -9201,7 +9549,7 @@ game ( game ( name "Klonoa - Empire of Dreams (USA)" description "Klonoa - Empire of Dreams (USA)" - rom ( name "Klonoa - Empire of Dreams (USA).gba" size 4194304 crc f74e1036 sha1 a0a298d9dba1ba15d04a42fc2eb35893d1a9569b ) + rom ( name "Klonoa - Empire of Dreams (USA).gba" size 4194304 crc f74e1036 sha1 a0a298d9dba1ba15d04a42fc2eb35893d1a9569b flags verified ) ) game ( @@ -9210,18 +9558,18 @@ game ( rom ( name "Klonoa - Empire of Dreams (Europe).gba" size 4194304 crc 69492530 sha1 e4a81713b134e0b7409708843dad2a4948b903ef ) ) -game ( - name "Klonoa 2 - Dream Champ Tournament (USA) (Virtual Console)" - description "Klonoa 2 - Dream Champ Tournament (USA) (Virtual Console)" - rom ( name "Klonoa 2 - Dream Champ Tournament (USA) (Virtual Console).gba" size 4194304 crc 766c7f9a sha1 455c6f19a703b2bd54a9a3a9588964239965e6db ) -) - game ( name "Klonoa 2 - Dream Champ Tournament (USA)" description "Klonoa 2 - Dream Champ Tournament (USA)" rom ( name "Klonoa 2 - Dream Champ Tournament (USA).gba" size 4194304 crc 8bd23a7f sha1 35c05676e65fd4c92220861662cd3709342f36e2 ) ) +game ( + name "Klonoa 2 - Dream Champ Tournament (USA) (Virtual Console)" + description "Klonoa 2 - Dream Champ Tournament (USA) (Virtual Console)" + rom ( name "Klonoa 2 - Dream Champ Tournament (USA) (Virtual Console).gba" size 4194304 crc 766c7f9a sha1 455c6f19a703b2bd54a9a3a9588964239965e6db ) +) + game ( name "Klonoa Heroes - Densetsu no Star Medal (Japan)" description "Klonoa Heroes - Densetsu no Star Medal (Japan)" @@ -9300,6 +9648,12 @@ game ( rom ( name "Konami Krazy Racers (Europe).gba" size 4194304 crc cfec0650 sha1 90a0035818ba0ab2a0c6ea45dc7eff2eb7296970 flags verified ) ) +game ( + name "Konami Krazy Racers (USA) (Beta)" + description "Konami Krazy Racers (USA) (Beta)" + rom ( name "Konami Krazy Racers (USA) (Beta).gba" size 4194304 crc 5f2ae8fe sha1 329b82282d633d1162f9afb3334c035b10b91e72 ) +) + game ( name "Konami Krazy Racers (USA) (Virtual Console)" description "Konami Krazy Racers (USA) (Virtual Console)" @@ -9313,9 +9667,9 @@ game ( ) game ( - name "Konami Krazy Racers (USA) (Beta)" - description "Konami Krazy Racers (USA) (Beta)" - rom ( name "Konami Krazy Racers (USA) (Beta).gba" size 4194304 crc 5f2ae8fe sha1 329b82282d633d1162f9afb3334c035b10b91e72 ) + name "Konami Wai Wai Racing Advance (Japan) (Virtual Console)" + description "Konami Wai Wai Racing Advance (Japan) (Virtual Console)" + rom ( name "Konami Wai Wai Racing Advance (Japan) (Virtual Console).gba" size 4194304 crc f424858f sha1 29f850ea1a9900446a0e1ce8ef1c2fd85341f242 ) ) game ( @@ -9324,12 +9678,6 @@ game ( rom ( name "Konami Wai Wai Racing Advance (Japan).gba" size 4194304 crc aa039a8a sha1 e3549b9b7d7208b88e368e7b7a59e31eec8b1da6 ) ) -game ( - name "Konami Wai Wai Racing Advance (Japan) (Virtual Console)" - description "Konami Wai Wai Racing Advance (Japan) (Virtual Console)" - rom ( name "Konami Wai Wai Racing Advance (Japan) (Virtual Console).gba" size 4194304 crc f424858f sha1 29f850ea1a9900446a0e1ce8ef1c2fd85341f242 ) -) - game ( name "Konchuu Monster - Battle Master (Japan)" description "Konchuu Monster - Battle Master (Japan)" @@ -9396,6 +9744,12 @@ game ( rom ( name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan).gba" size 16777216 crc b7827f20 sha1 854a76c49f6e83d8ee9dd42098ce1fc7236af855 flags verified ) ) +game ( + name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan) (Rev 1)" + description "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan) (Rev 1)" + rom ( name "Konjiki no Gashbell!! - Unare! Yuujou no Zakeru 2 (Japan) (Rev 1).gba" size 16777216 crc f40e19a9 sha1 a8a68c714497c8ba68ba47636d8156182a5c3b7c ) +) + game ( name "Konjiki no Gashbell!! The Card Battle for GBA (Japan)" description "Konjiki no Gashbell!! The Card Battle for GBA (Japan)" @@ -9409,9 +9763,9 @@ game ( ) game ( - name "Koro Koro Puzzle - Happy Panechu! (Japan)" - description "Koro Koro Puzzle - Happy Panechu! (Japan)" - rom ( name "Koro Koro Puzzle - Happy Panechu! (Japan).gba" size 4194304 crc 0bfe46e9 sha1 40cb751d119a49be0cd44cf0491c93ebc8795ef0 ) + name "Korokoro Puzzle - Happy Panecchu! (Japan)" + description "Korokoro Puzzle - Happy Panecchu! (Japan)" + rom ( name "Korokoro Puzzle - Happy Panecchu! (Japan).gba" size 4194304 crc 0bfe46e9 sha1 40cb751d119a49be0cd44cf0491c93ebc8795ef0 ) ) game ( @@ -9451,9 +9805,9 @@ game ( ) game ( - name "Koutetsu Teikoku from HOT-B (Japan)" - description "Koutetsu Teikoku from HOT-B (Japan)" - rom ( name "Koutetsu Teikoku from HOT-B (Japan).gba" size 4194304 crc cdfac4ee sha1 7253d2d036429b478e4132de4901417dd840ae1a ) + name "Koutetsu Teikoku (Japan)" + description "Koutetsu Teikoku (Japan)" + rom ( name "Koutetsu Teikoku (Japan).gba" size 4194304 crc cdfac4ee sha1 7253d2d036429b478e4132de4901417dd840ae1a ) ) game ( @@ -9577,9 +9931,9 @@ game ( ) game ( - name "Legend of Dynamic Goushouden - Houkai no Rondo (Japan)" - description "Legend of Dynamic Goushouden - Houkai no Rondo (Japan)" - rom ( name "Legend of Dynamic Goushouden - Houkai no Rondo (Japan).gba" size 8388608 crc 67f18f8e sha1 8a037eff3a44b1667ec5e81ca8c1ff03537366b2 ) + name "Legend of Dynamic - Goushouden - Houkai no Rondo (Japan)" + description "Legend of Dynamic - Goushouden - Houkai no Rondo (Japan)" + rom ( name "Legend of Dynamic - Goushouden - Houkai no Rondo (Japan).gba" size 8388608 crc 67f18f8e sha1 8a037eff3a44b1667ec5e81ca8c1ff03537366b2 ) ) game ( @@ -9702,12 +10056,6 @@ game ( rom ( name "LEGO Racers 2 (Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 7a1dc458 sha1 a4da0237646a4f56296465b92c659f3e7438ad98 ) ) -game ( - name "LEGO Soccer Mania (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" - description "LEGO Soccer Mania (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" - rom ( name "LEGO Soccer Mania (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 73ef3a35 sha1 05799b99395aba04dfe5ae8af019e4d70cb8e61b ) -) - game ( name "LEGO Star Wars - The Video Game (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" description "LEGO Star Wars - The Video Game (USA, Europe) (En,Fr,De,Es,It,Nl,Da)" @@ -9801,13 +10149,13 @@ game ( game ( name "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl) (Rev 1)" description "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl) (Rev 1)" - rom ( name "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl) (Rev 1).gba" size 8388608 crc e7bc4ef1 sha1 a4e86401593c1763fdd70c6e1f7b4ccec7101db7 flags verified ) + rom ( name "Lilo & Stitch (Europe) (En,Fr,De,Es,It,Nl) (Rev 1).gba" size 8388608 crc e7bc4ef1 sha1 a4e86401593c1763fdd70c6e1f7b4ccec7101db7 ) ) game ( name "Lilo & Stitch (USA)" description "Lilo & Stitch (USA)" - rom ( name "Lilo & Stitch (USA).gba" size 8388608 crc 542aa4ac sha1 b86e22f7009ae20c0d8efc51ab7c61c0cee21a0c ) + rom ( name "Lilo & Stitch (USA).gba" size 8388608 crc 542aa4ac sha1 b86e22f7009ae20c0d8efc51ab7c61c0cee21a0c flags verified ) ) game ( @@ -10020,6 +10368,12 @@ game ( rom ( name "Lufia - The Ruins of Lore (USA).gba" size 8388608 crc de5ffcbc sha1 a2b7e80a6c7d586ebeec77c8a2c2545fe27e0592 ) ) +game ( + name "Luggage Retrieval Officer (World) (Aftermarket) (Unl)" + description "Luggage Retrieval Officer (World) (Aftermarket) (Unl)" + rom ( name "Luggage Retrieval Officer (World) (Aftermarket) (Unl).gba" size 3336260 crc 5aa30d90 sha1 84c9b2d50c8af74b8b04f88af367d9fac1a24ef6 ) +) + game ( name "Lunar Legend (Japan)" description "Lunar Legend (Japan)" @@ -10047,7 +10401,7 @@ game ( game ( name "Madagascar (Europe)" description "Madagascar (Europe)" - rom ( name "Madagascar (Europe).gba" size 8388608 crc 394f2126 sha1 30e85193a92ae6fa4dd1c54ea76d629276789657 ) + rom ( name "Madagascar (Europe).gba" size 8388608 crc 394f2126 sha1 30e85193a92ae6fa4dd1c54ea76d629276789657 flags verified ) ) game ( @@ -10191,7 +10545,7 @@ game ( game ( name "Magical Quest 2 Starring Mickey & Minnie (Europe) (En,Fr,De)" description "Magical Quest 2 Starring Mickey & Minnie (Europe) (En,Fr,De)" - rom ( name "Magical Quest 2 Starring Mickey & Minnie (Europe) (En,Fr,De).gba" size 4194304 crc f9498038 sha1 1cac78eb9f6a9079f1a02d48dcd1ce4c7a81350b ) + rom ( name "Magical Quest 2 Starring Mickey & Minnie (Europe) (En,Fr,De).gba" size 4194304 crc f9498038 sha1 1cac78eb9f6a9079f1a02d48dcd1ce4c7a81350b flags verified ) ) game ( @@ -10309,15 +10663,15 @@ game ( ) game ( - name "Manga-ka Debut Monogatari (Japan) (Rev 1)" - description "Manga-ka Debut Monogatari (Japan) (Rev 1)" - rom ( name "Manga-ka Debut Monogatari (Japan) (Rev 1).gba" size 4194304 crc f0c22c62 sha1 78c57d1062830074166da3192b01d0d0ae9afaeb ) + name "Manga-ka Debut Monogatari - Akogare! Manga Ka Ikusei Game! (Japan) (Rev 1)" + description "Manga-ka Debut Monogatari - Akogare! Manga Ka Ikusei Game! (Japan) (Rev 1)" + rom ( name "Manga-ka Debut Monogatari - Akogare! Manga Ka Ikusei Game! (Japan) (Rev 1).gba" size 4194304 crc f0c22c62 sha1 78c57d1062830074166da3192b01d0d0ae9afaeb ) ) game ( - name "Manga-ka Debut Monogatari (Japan)" - description "Manga-ka Debut Monogatari (Japan)" - rom ( name "Manga-ka Debut Monogatari (Japan).gba" size 4194304 crc 61a602d7 sha1 5f7c1b88b8c7caa57a0af81cd3ae74171abe50d1 ) + name "Manga-ka Debut Monogatari - Akogare! Manga Ka Ikusei Game! (Japan)" + description "Manga-ka Debut Monogatari - Akogare! Manga Ka Ikusei Game! (Japan)" + rom ( name "Manga-ka Debut Monogatari - Akogare! Manga Ka Ikusei Game! (Japan).gba" size 4194304 crc 61a602d7 sha1 5f7c1b88b8c7caa57a0af81cd3ae74171abe50d1 ) ) game ( @@ -10356,6 +10710,12 @@ game ( rom ( name "Marie, Elie & Anis no Atelier - Soyokaze kara no Dengon (Japan).gba" size 8388608 crc 1b70a454 sha1 0dbde8bcaa9e4bdc201674a0d66c6ce64242eb4b ) ) +game ( + name "Mario & Luigi (USA) (Demo) (Kiosk, E3 2003)" + description "Mario & Luigi (USA) (Demo) (Kiosk, E3 2003)" + rom ( name "Mario & Luigi (USA) (Demo) (Kiosk, E3 2003).gba" size 8388608 crc 2d01a8df sha1 4265af33441ad7b16566ea6c6a2803dc8e9cdf9b ) +) + game ( name "Mario & Luigi - Superstar Saga (USA) (Demo) (Kiosk)" description "Mario & Luigi - Superstar Saga (USA) (Demo) (Kiosk)" @@ -10512,6 +10872,18 @@ game ( rom ( name "Mario Kart Advance (Japan).gba" size 4194304 crc 30e99fcd sha1 88ffde363b05264a99a4d5ada0c80a00196a94d7 flags verified ) ) +game ( + name "Mario Kart XXL (Europe) (Demo)" + description "Mario Kart XXL (Europe) (Demo)" + rom ( name "Mario Kart XXL (Europe) (Demo).gba" size 4194304 crc e3075601 sha1 ba1e75f780c41e737922f090dcb17526f1fd7a01 ) +) + +game ( + name "Mario Party Advance (Europe) (En,Fr,De,Es,It) (Virtual Console)" + description "Mario Party Advance (Europe) (En,Fr,De,Es,It) (Virtual Console)" + rom ( name "Mario Party Advance (Europe) (En,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 46c66f40 sha1 34d13fd8cca31a77eeebf9c864a4388969f975c4 ) +) + game ( name "Mario Party Advance (USA) (Virtual Console)" description "Mario Party Advance (USA) (Virtual Console)" @@ -10543,9 +10915,9 @@ game ( ) game ( - name "Mario Party Advance (Europe) (En,Fr,De,Es,It) (Virtual Console)" - description "Mario Party Advance (Europe) (En,Fr,De,Es,It) (Virtual Console)" - rom ( name "Mario Party Advance (Europe) (En,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 46c66f40 sha1 34d13fd8cca31a77eeebf9c864a4388969f975c4 ) + name "Mario Pinball Land (USA, Australia)" + description "Mario Pinball Land (USA, Australia)" + rom ( name "Mario Pinball Land (USA, Australia).gba" size 8388608 crc 70a6d2c1 sha1 3fdcd3bb30d61b4dd6829dbdc1a0ac116618b87d flags verified ) ) game ( @@ -10561,9 +10933,9 @@ game ( ) game ( - name "Mario Pinball Land (USA, Australia)" - description "Mario Pinball Land (USA, Australia)" - rom ( name "Mario Pinball Land (USA, Australia).gba" size 8388608 crc 70a6d2c1 sha1 3fdcd3bb30d61b4dd6829dbdc1a0ac116618b87d flags verified ) + name "Mario Power Tennis (Europe) (En,Fr,De,Es,It) (Virtual Console)" + description "Mario Power Tennis (Europe) (En,Fr,De,Es,It) (Virtual Console)" + rom ( name "Mario Power Tennis (Europe) (En,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 851a44cb sha1 24087080476ce04853455fd82f09c4d8c65604d1 ) ) game ( @@ -10572,12 +10944,6 @@ game ( rom ( name "Mario Power Tennis (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc c8db4f60 sha1 d61990974040d405b5bf8436ac8e1e0beb0f7964 flags verified ) ) -game ( - name "Mario Power Tennis (Europe) (En,Fr,De,Es,It) (Virtual Console)" - description "Mario Power Tennis (Europe) (En,Fr,De,Es,It) (Virtual Console)" - rom ( name "Mario Power Tennis (Europe) (En,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 851a44cb sha1 24087080476ce04853455fd82f09c4d8c65604d1 ) -) - game ( name "Mario Tennis - Power Tour (USA, Australia) (En,Fr,De,Es,It)" description "Mario Tennis - Power Tour (USA, Australia) (En,Fr,De,Es,It)" @@ -10608,6 +10974,12 @@ game ( rom ( name "Mario vs. Donkey Kong (Japan) (Demo) (Kiosk, GameCube).gba" size 16777216 crc b3642431 sha1 e7389b36573f7e32d53ae9acfdba744389c2f6c2 flags verified ) ) +game ( + name "Mario vs. Donkey Kong (USA) (Demo) (Kiosk, GameCube)" + description "Mario vs. Donkey Kong (USA) (Demo) (Kiosk, GameCube)" + rom ( name "Mario vs. Donkey Kong (USA) (Demo) (Kiosk, GameCube).gba" size 16777216 crc 25505164 sha1 68eebe6dbcf8973ed7426a793185db202a01288f flags verified ) +) + game ( name "Mario vs. Donkey Kong (USA, Australia)" description "Mario vs. Donkey Kong (USA, Australia)" @@ -10626,12 +10998,6 @@ game ( rom ( name "Mario vs. Donkey Kong (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc ca030d61 sha1 c645798ea9cf94e2fd8826ea96a5971a7aeb52b7 flags verified ) ) -game ( - name "Mario vs. Donkey Kong (USA) (Demo) (Kiosk, GameCube)" - description "Mario vs. Donkey Kong (USA) (Demo) (Kiosk, GameCube)" - rom ( name "Mario vs. Donkey Kong (USA) (Demo) (Kiosk, GameCube).gba" size 16777216 crc 25505164 sha1 68eebe6dbcf8973ed7426a793185db202a01288f flags verified ) -) - game ( name "Marvel - Ultimate Alliance (USA)" description "Marvel - Ultimate Alliance (USA)" @@ -10665,7 +11031,7 @@ game ( game ( name "Mat Hoffman's Pro BMX (USA, Europe)" description "Mat Hoffman's Pro BMX (USA, Europe)" - rom ( name "Mat Hoffman's Pro BMX (USA, Europe).gba" size 4194304 crc a333fa51 sha1 df0345c31ca3cad51cef7adae8c6fdadf81b3a97 ) + rom ( name "Mat Hoffman's Pro BMX (USA, Europe).gba" size 4194304 crc a333fa51 sha1 df0345c31ca3cad51cef7adae8c6fdadf81b3a97 flags verified ) ) game ( @@ -10680,18 +11046,18 @@ game ( rom ( name "Mat Hoffman's Pro BMX 2 (USA, Europe).gba" size 8388608 crc e7fa71c6 sha1 d12bc188404bfb6d012b9ce1cf7302762d934832 ) ) -game ( - name "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan) (Rev 1)" - description "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan) (Rev 1)" - rom ( name "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan) (Rev 1).gba" size 8388608 crc d647ab18 sha1 3489569fa8a3c6a750c5cb0048915da78c5f40ab ) -) - game ( name "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan)" description "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan)" rom ( name "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan).gba" size 8388608 crc 4ebdad86 sha1 9e1d0d5d5454d544ab85b34ad0e50fad7b54487c flags verified ) ) +game ( + name "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan) (Rev 1)" + description "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan) (Rev 1)" + rom ( name "Matantei Loki Ragnarok - Gensou no Labyrinth (Japan) (Rev 1).gba" size 8388608 crc d647ab18 sha1 3489569fa8a3c6a750c5cb0048915da78c5f40ab ) +) + game ( name "Matchbox Cross Town Heroes (USA)" description "Matchbox Cross Town Heroes (USA)" @@ -10770,6 +11136,12 @@ game ( rom ( name "Medabots - Metabee (Europe) (Virtual Console).gba" size 8388608 crc 3524f206 sha1 5a4d269998829d7e41fdb014ffa11584ea1f8aa6 ) ) +game ( + name "Medabots - Metabee (Europe)" + description "Medabots - Metabee (Europe)" + rom ( name "Medabots - Metabee (Europe).gba" size 8388608 crc 50927f3e sha1 cd3d674e88f40a0707b150c4293588a659001d29 ) +) + game ( name "Medabots - Metabee (Spain)" description "Medabots - Metabee (Spain)" @@ -10789,9 +11161,9 @@ game ( ) game ( - name "Medabots - Metabee (Europe)" - description "Medabots - Metabee (Europe)" - rom ( name "Medabots - Metabee (Europe).gba" size 8388608 crc 50927f3e sha1 cd3d674e88f40a0707b150c4293588a659001d29 ) + name "Medabots - Rokusho (USA)" + description "Medabots - Rokusho (USA)" + rom ( name "Medabots - Rokusho (USA).gba" size 8388608 crc e144ded2 sha1 c4572428ea97b302f699a3b4eba2a1f0e87c1c9c ) ) game ( @@ -10800,12 +11172,6 @@ game ( rom ( name "Medabots - Rokusho (Europe).gba" size 8388608 crc a519feb5 sha1 fc44b80f3e71effc33d8e05a74888cb885c32eb0 flags verified ) ) -game ( - name "Medabots - Rokusho (Spain)" - description "Medabots - Rokusho (Spain)" - rom ( name "Medabots - Rokusho (Spain).gba" size 8388608 crc 046d86c4 sha1 90fe7f2927c592aabc9b33d0df00d92046c5cb92 ) -) - game ( name "Medabots - Rokusho (USA) (Virtual Console)" description "Medabots - Rokusho (USA) (Virtual Console)" @@ -10819,15 +11185,9 @@ game ( ) game ( - name "Medabots - Rokusho (USA)" - description "Medabots - Rokusho (USA)" - rom ( name "Medabots - Rokusho (USA).gba" size 8388608 crc e144ded2 sha1 c4572428ea97b302f699a3b4eba2a1f0e87c1c9c ) -) - -game ( - name "Medabots AX - Metabee Ver. (Europe) (En,Fr,De,Es,It)" - description "Medabots AX - Metabee Ver. (Europe) (En,Fr,De,Es,It)" - rom ( name "Medabots AX - Metabee Ver. (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5f1e5a48 sha1 130c908d24ba3e422fd8db84e683bacc87235e78 flags verified ) + name "Medabots - Rokusho (Spain)" + description "Medabots - Rokusho (Spain)" + rom ( name "Medabots - Rokusho (Spain).gba" size 8388608 crc 046d86c4 sha1 90fe7f2927c592aabc9b33d0df00d92046c5cb92 ) ) game ( @@ -10836,6 +11196,12 @@ game ( rom ( name "Medabots AX - Metabee Ver. (USA).gba" size 8388608 crc 03294511 sha1 80c024df6d40e499776665d7f0c494a252973048 ) ) +game ( + name "Medabots AX - Metabee Ver. (Europe) (En,Fr,De,Es,It)" + description "Medabots AX - Metabee Ver. (Europe) (En,Fr,De,Es,It)" + rom ( name "Medabots AX - Metabee Ver. (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 5f1e5a48 sha1 130c908d24ba3e422fd8db84e683bacc87235e78 flags verified ) +) + game ( name "Medabots AX - Metabee Ver. (USA) (Virtual Console)" description "Medabots AX - Metabee Ver. (USA) (Virtual Console)" @@ -10878,6 +11244,12 @@ game ( rom ( name "Medal of Honor - Infiltrator (USA, Europe) (En,Fr,De).gba" size 16777216 crc f23150a4 sha1 47761911475e9548c81fed78e3d3336ddae89a58 flags verified ) ) +game ( + name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Zoo Digital)" + description "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Zoo Digital)" + rom ( name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Zoo Digital).gba" size 8388608 crc 72b4cf20 sha1 abb26d759ef729d21e41a913fc6c1ce4ab77149f ) +) + game ( name "Medal of Honor - Underground (USA)" description "Medal of Honor - Underground (USA)" @@ -10890,12 +11262,6 @@ game ( rom ( name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Ubi Soft).gba" size 8388608 crc 9db145b8 sha1 e43aaba3f925443cfccf9294b870024a9c71a9a9 ) ) -game ( - name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Zoo Digital)" - description "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Zoo Digital)" - rom ( name "Medal of Honor - Underground (Europe) (En,Fr,Es,It) (Zoo Digital).gba" size 8388608 crc 72b4cf20 sha1 abb26d759ef729d21e41a913fc6c1ce4ab77149f ) -) - game ( name "Medal of Honor Advance (Japan)" description "Medal of Honor Advance (Japan)" @@ -10993,375 +11359,375 @@ game ( ) game ( - name "Mega Man & Bass (USA) (Virtual Console)" - description "Mega Man & Bass (USA) (Virtual Console)" - rom ( name "Mega Man & Bass (USA) (Virtual Console).gba" size 8388608 crc b61f99d4 sha1 37db963a52aecec8018057cef3811860c3e889ed ) + name "Megaman - Battle Chip Challenge (USA) (Virtual Console)" + description "Megaman - Battle Chip Challenge (USA) (Virtual Console)" + rom ( name "Megaman - Battle Chip Challenge (USA) (Virtual Console).gba" size 8388608 crc 59fc1ef6 sha1 e936db20e9cf923dc10c6c1dc14bc7ed6b220080 ) ) game ( - name "Mega Man & Bass (USA)" - description "Mega Man & Bass (USA)" - rom ( name "Mega Man & Bass (USA).gba" size 8388608 crc eea68c2e sha1 7610847b331870d4338e5ac894b36e55e2bec5a0 ) + name "Megaman - Battle Chip Challenge (Europe) (Virtual Console)" + description "Megaman - Battle Chip Challenge (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Chip Challenge (Europe) (Virtual Console).gba" size 8388608 crc 24046bf2 sha1 f0776ad33eb01a47207a076d95b534145223371d ) ) game ( - name "Mega Man & Bass (Europe)" - description "Mega Man & Bass (Europe)" - rom ( name "Mega Man & Bass (Europe).gba" size 8388608 crc 01b4d95e sha1 5d6f8fb1f52803a54e9857e53d0b88173cf8f48a flags verified ) + name "Megaman - Battle Chip Challenge (USA)" + description "Megaman - Battle Chip Challenge (USA)" + rom ( name "Megaman - Battle Chip Challenge (USA).gba" size 8388608 crc 26be44fd sha1 72309736f3820470c6f372d6a05ad1f16bc5a946 ) ) game ( - name "Mega Man & Bass (Europe) (Virtual Console)" - description "Mega Man & Bass (Europe) (Virtual Console)" - rom ( name "Mega Man & Bass (Europe) (Virtual Console).gba" size 8388608 crc 6e140bfa sha1 37a188a250ff553a71144f8bbe92098c85c8006d ) + name "Megaman - Battle Chip Challenge (Europe)" + description "Megaman - Battle Chip Challenge (Europe)" + rom ( name "Megaman - Battle Chip Challenge (Europe).gba" size 8388608 crc 5b4631f9 sha1 f54486c8a0bb22cf0ece4297fb052d0a0f11e56d ) ) game ( - name "Mega Man Battle Chip Challenge (USA) (Virtual Console)" - description "Mega Man Battle Chip Challenge (USA) (Virtual Console)" - rom ( name "Mega Man Battle Chip Challenge (USA) (Virtual Console).gba" size 8388608 crc 59fc1ef6 sha1 e936db20e9cf923dc10c6c1dc14bc7ed6b220080 ) + name "Megaman - Battle Network (USA) (Virtual Console)" + description "Megaman - Battle Network (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network (USA) (Virtual Console).gba" size 8388608 crc 1d5d0cb6 sha1 a371765e107c30dc4ac37c2f114a785305f47a4c ) ) game ( - name "Mega Man Battle Chip Challenge (Europe) (Virtual Console)" - description "Mega Man Battle Chip Challenge (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Chip Challenge (Europe) (Virtual Console).gba" size 8388608 crc 24046bf2 sha1 f0776ad33eb01a47207a076d95b534145223371d ) + name "Megaman - Battle Network (Europe) (Virtual Console)" + description "Megaman - Battle Network (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network (Europe) (Virtual Console).gba" size 8388608 crc 1a16c13d sha1 0dcbc43d5d50401c0eab8bb5989055523ce90b10 ) ) game ( - name "Mega Man Battle Chip Challenge (USA)" - description "Mega Man Battle Chip Challenge (USA)" - rom ( name "Mega Man Battle Chip Challenge (USA).gba" size 8388608 crc 26be44fd sha1 72309736f3820470c6f372d6a05ad1f16bc5a946 ) + name "Megaman - Battle Network (USA)" + description "Megaman - Battle Network (USA)" + rom ( name "Megaman - Battle Network (USA).gba" size 8388608 crc 1d347971 sha1 a4fbae389654a6611d0597b1e9109cbbd32a132f ) ) game ( - name "Mega Man Battle Chip Challenge (Europe)" - description "Mega Man Battle Chip Challenge (Europe)" - rom ( name "Mega Man Battle Chip Challenge (Europe).gba" size 8388608 crc 5b4631f9 sha1 f54486c8a0bb22cf0ece4297fb052d0a0f11e56d ) + name "Megaman - Battle Network (Europe)" + description "Megaman - Battle Network (Europe)" + rom ( name "Megaman - Battle Network (Europe).gba" size 8388608 crc 1a7fb4fa sha1 b017b6054ffafc012be9adee785819b17706cabc flags verified ) ) game ( - name "Mega Man Battle Network (USA)" - description "Mega Man Battle Network (USA)" - rom ( name "Mega Man Battle Network (USA).gba" size 8388608 crc 1d347971 sha1 a4fbae389654a6611d0597b1e9109cbbd32a132f ) + name "Megaman - Battle Network 2 (USA)" + description "Megaman - Battle Network 2 (USA)" + rom ( name "Megaman - Battle Network 2 (USA).gba" size 8388608 crc 6d961f82 sha1 601b5012f77001d2c5c11b31304afafc45a70d0b ) ) game ( - name "Mega Man Battle Network (Europe)" - description "Mega Man Battle Network (Europe)" - rom ( name "Mega Man Battle Network (Europe).gba" size 8388608 crc 1a7fb4fa sha1 b017b6054ffafc012be9adee785819b17706cabc ) + name "Megaman - Battle Network 2 (Europe)" + description "Megaman - Battle Network 2 (Europe)" + rom ( name "Megaman - Battle Network 2 (Europe).gba" size 8388608 crc 66341f3b sha1 13d8c1978cbcd9ca2a127168544fda176e0a4d6c ) ) game ( - name "Mega Man Battle Network (USA) (Virtual Console)" - description "Mega Man Battle Network (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network (USA) (Virtual Console).gba" size 8388608 crc 1d5d0cb6 sha1 a371765e107c30dc4ac37c2f114a785305f47a4c ) + name "Megaman - Battle Network 2 (USA) (Debug Version)" + description "Megaman - Battle Network 2 (USA) (Debug Version)" + rom ( name "Megaman - Battle Network 2 (USA) (Debug Version).gba" size 8388608 crc c3aabd70 sha1 d8968ac6c33f376d8f6ce6205b53756434a8d2ac ) ) game ( - name "Mega Man Battle Network (Europe) (Virtual Console)" - description "Mega Man Battle Network (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network (Europe) (Virtual Console).gba" size 8388608 crc 1a16c13d sha1 0dcbc43d5d50401c0eab8bb5989055523ce90b10 ) + name "Megaman - Battle Network 2 (USA, Europe) (Virtual Console)" + description "Megaman - Battle Network 2 (USA, Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 2 (USA, Europe) (Virtual Console).gba" size 8388608 crc 5e88c34b sha1 d6b574203cc393f292a9825fcec64e72b3b2a11b flags verified ) ) game ( - name "Mega Man Battle Network 2 (USA) (Debug Version)" - description "Mega Man Battle Network 2 (USA) (Debug Version)" - rom ( name "Mega Man Battle Network 2 (USA) (Debug Version).gba" size 33554432 crc fbdadaa7 sha1 3bc2a627a859431db0f40f755fbc2857936e23b2 ) + name "Megaman - Battle Network 3 - Blue Version (USA) (Virtual Console)" + description "Megaman - Battle Network 3 - Blue Version (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 3 - Blue Version (USA) (Virtual Console).gba" size 8388608 crc edd7106e sha1 6e30310f3994803e56170f6d67c5f154a5d91ccb flags verified ) ) game ( - name "Mega Man Battle Network 2 (USA, Europe) (Virtual Console)" - description "Mega Man Battle Network 2 (USA, Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 2 (USA, Europe) (Virtual Console).gba" size 8388608 crc 5e88c34b sha1 d6b574203cc393f292a9825fcec64e72b3b2a11b flags verified ) + name "Megaman - Battle Network 3 - Blue Version (Europe) (Virtual Console)" + description "Megaman - Battle Network 3 - Blue Version (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 3 - Blue Version (Europe) (Virtual Console).gba" size 8388608 crc 3213fc2d sha1 a9fe51d3ffd7488739821b895b45cf91c10a3108 ) ) game ( - name "Mega Man Battle Network 2 (USA)" - description "Mega Man Battle Network 2 (USA)" - rom ( name "Mega Man Battle Network 2 (USA).gba" size 8388608 crc 6d961f82 sha1 601b5012f77001d2c5c11b31304afafc45a70d0b ) + name "Megaman - Battle Network 3 - Blue Version (USA)" + description "Megaman - Battle Network 3 - Blue Version (USA)" + rom ( name "Megaman - Battle Network 3 - Blue Version (USA).gba" size 8388608 crc c0c780f9 sha1 3d21905b6e860d39a00ba643779776de4c73c411 flags verified ) ) game ( - name "Mega Man Battle Network 2 (Europe)" - description "Mega Man Battle Network 2 (Europe)" - rom ( name "Mega Man Battle Network 2 (Europe).gba" size 8388608 crc 66341f3b sha1 13d8c1978cbcd9ca2a127168544fda176e0a4d6c ) + name "Megaman - Battle Network 3 - Blue Version (Europe)" + description "Megaman - Battle Network 3 - Blue Version (Europe)" + rom ( name "Megaman - Battle Network 3 - Blue Version (Europe).gba" size 8388608 crc 1f036cba sha1 9cb052728cae18864a012e7598119ca7b93eea67 ) ) game ( - name "Mega Man Battle Network 3 - Blue (Europe)" - description "Mega Man Battle Network 3 - Blue (Europe)" - rom ( name "Mega Man Battle Network 3 - Blue (Europe).gba" size 8388608 crc 1f036cba sha1 9cb052728cae18864a012e7598119ca7b93eea67 ) + name "Megaman - Battle Network 3 - White Version (USA)" + description "Megaman - Battle Network 3 - White Version (USA)" + rom ( name "Megaman - Battle Network 3 - White Version (USA).gba" size 8388608 crc 0be4410a sha1 ff45038ae6d01cde4eae25a02dcb8bed29e07a6f flags verified ) ) game ( - name "Mega Man Battle Network 3 - Blue (Europe) (Virtual Console)" - description "Mega Man Battle Network 3 - Blue (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 3 - Blue (Europe) (Virtual Console).gba" size 8388608 crc 3213fc2d sha1 a9fe51d3ffd7488739821b895b45cf91c10a3108 ) + name "Megaman - Battle Network 3 - White Version (Europe)" + description "Megaman - Battle Network 3 - White Version (Europe)" + rom ( name "Megaman - Battle Network 3 - White Version (Europe).gba" size 8388608 crc 23d0a981 sha1 2942a890c369569e163a60f831150305ca0828fc ) ) game ( - name "Mega Man Battle Network 3 - Blue Version (USA) (Virtual Console)" - description "Mega Man Battle Network 3 - Blue Version (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 3 - Blue Version (USA) (Virtual Console).gba" size 8388608 crc edd7106e sha1 6e30310f3994803e56170f6d67c5f154a5d91ccb flags verified ) + name "Megaman - Battle Network 3 - White Version (USA) (Virtual Console)" + description "Megaman - Battle Network 3 - White Version (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 3 - White Version (USA) (Virtual Console).gba" size 8388608 crc f1c5ac80 sha1 1f0762b7c817211e855f4f50c2b11585d0893be9 ) ) game ( - name "Mega Man Battle Network 3 - Blue Version (USA)" - description "Mega Man Battle Network 3 - Blue Version (USA)" - rom ( name "Mega Man Battle Network 3 - Blue Version (USA).gba" size 8388608 crc c0c780f9 sha1 3d21905b6e860d39a00ba643779776de4c73c411 flags verified ) + name "Megaman - Battle Network 3 - White Version (Europe) (Virtual Console)" + description "Megaman - Battle Network 3 - White Version (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 3 - White Version (Europe) (Virtual Console).gba" size 8388608 crc d9f1440b sha1 e0bd967c2296ca5a515e8b6231d4959336c1278d ) ) game ( - name "Mega Man Battle Network 3 - White (Europe)" - description "Mega Man Battle Network 3 - White (Europe)" - rom ( name "Mega Man Battle Network 3 - White (Europe).gba" size 8388608 crc 23d0a981 sha1 2942a890c369569e163a60f831150305ca0828fc ) + name "Megaman - Battle Network 4 - Blue Moon (USA) (Virtual Console)" + description "Megaman - Battle Network 4 - Blue Moon (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 4 - Blue Moon (USA) (Virtual Console).gba" size 8388608 crc 739b7ec4 sha1 62a0169f0fe00e5f8184475a20a36877d1063f63 flags verified ) ) game ( - name "Mega Man Battle Network 3 - White (Europe) (Virtual Console)" - description "Mega Man Battle Network 3 - White (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 3 - White (Europe) (Virtual Console).gba" size 8388608 crc d9f1440b sha1 e0bd967c2296ca5a515e8b6231d4959336c1278d ) + name "Megaman - Battle Network 4 - Blue Moon (Europe) (Virtual Console)" + description "Megaman - Battle Network 4 - Blue Moon (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 4 - Blue Moon (Europe) (Virtual Console).gba" size 8388608 crc ad89f27d sha1 0fbf2b2f53f0a32e893e2593e2d7c542b5fcac99 ) ) game ( - name "Mega Man Battle Network 3 - White Version (USA) (Virtual Console)" - description "Mega Man Battle Network 3 - White Version (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 3 - White Version (USA) (Virtual Console).gba" size 8388608 crc f1c5ac80 sha1 1f0762b7c817211e855f4f50c2b11585d0893be9 ) + name "Megaman - Battle Network 4 - Blue Moon (USA)" + description "Megaman - Battle Network 4 - Blue Moon (USA)" + rom ( name "Megaman - Battle Network 4 - Blue Moon (USA).gba" size 8388608 crc 758a46e9 sha1 5e017c803ddc768efb8010314b46bc17e9757f71 flags verified ) ) game ( - name "Mega Man Battle Network 3 - White Version (USA)" - description "Mega Man Battle Network 3 - White Version (USA)" - rom ( name "Mega Man Battle Network 3 - White Version (USA).gba" size 8388608 crc 0be4410a sha1 ff45038ae6d01cde4eae25a02dcb8bed29e07a6f flags verified ) + name "Megaman - Battle Network 4 - Blue Moon (Europe)" + description "Megaman - Battle Network 4 - Blue Moon (Europe)" + rom ( name "Megaman - Battle Network 4 - Blue Moon (Europe).gba" size 8388608 crc 48758316 sha1 a05e8dce26b5134001337e193d49958be2081598 flags verified ) ) game ( - name "Mega Man Battle Network 4 - Blue Moon (USA)" - description "Mega Man Battle Network 4 - Blue Moon (USA)" - rom ( name "Mega Man Battle Network 4 - Blue Moon (USA).gba" size 8388608 crc 758a46e9 sha1 5e017c803ddc768efb8010314b46bc17e9757f71 flags verified ) + name "Megaman - Battle Network 4 - Red Sun (USA)" + description "Megaman - Battle Network 4 - Red Sun (USA)" + rom ( name "Megaman - Battle Network 4 - Red Sun (USA).gba" size 8388608 crc 2120695c sha1 a97e96a7da03abd70f7953328e511b9fa29179f1 flags verified ) ) game ( - name "Mega Man Battle Network 4 - Blue Moon (Europe)" - description "Mega Man Battle Network 4 - Blue Moon (Europe)" - rom ( name "Mega Man Battle Network 4 - Blue Moon (Europe).gba" size 8388608 crc 48758316 sha1 a05e8dce26b5134001337e193d49958be2081598 ) + name "Megaman - Battle Network 4 - Red Sun (Europe)" + description "Megaman - Battle Network 4 - Red Sun (Europe)" + rom ( name "Megaman - Battle Network 4 - Red Sun (Europe).gba" size 8388608 crc 0cb136c2 sha1 21af9f7805a27729e770928f939acedd6ae27c1c ) ) game ( - name "Mega Man Battle Network 4 - Blue Moon (USA) (Virtual Console)" - description "Mega Man Battle Network 4 - Blue Moon (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 4 - Blue Moon (USA) (Virtual Console).gba" size 8388608 crc 739b7ec4 sha1 62a0169f0fe00e5f8184475a20a36877d1063f63 flags verified ) + name "Megaman - Battle Network 4 - Red Sun (USA) (Virtual Console)" + description "Megaman - Battle Network 4 - Red Sun (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 4 - Red Sun (USA) (Virtual Console).gba" size 8388608 crc 12e7ab52 sha1 07426328dbb4a3aea763e75c8ffe6de482ff69d0 flags verified ) ) game ( - name "Mega Man Battle Network 4 - Blue Moon (Europe) (Virtual Console)" - description "Mega Man Battle Network 4 - Blue Moon (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 4 - Blue Moon (Europe) (Virtual Console).gba" size 8388608 crc ad89f27d sha1 0fbf2b2f53f0a32e893e2593e2d7c542b5fcac99 ) + name "Megaman - Battle Network 4 - Red Sun (Europe) (Virtual Console)" + description "Megaman - Battle Network 4 - Red Sun (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 4 - Red Sun (Europe) (Virtual Console).gba" size 8388608 crc cb3bbf74 sha1 36d83a1509d28b0c09365466cc1481c919d84cb0 ) ) game ( - name "Mega Man Battle Network 4 - Red Sun (USA) (Virtual Console)" - description "Mega Man Battle Network 4 - Red Sun (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 4 - Red Sun (USA) (Virtual Console).gba" size 8388608 crc 12e7ab52 sha1 07426328dbb4a3aea763e75c8ffe6de482ff69d0 flags verified ) + name "Megaman - Battle Network 5 - Team Colonel (USA) (Virtual Console)" + description "Megaman - Battle Network 5 - Team Colonel (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 5 - Team Colonel (USA) (Virtual Console).gba" size 8388608 crc 78dd4edc sha1 c715f1d01e016ad6890ebc8ec90120bc3b146a7e ) ) game ( - name "Mega Man Battle Network 4 - Red Sun (Europe) (Virtual Console)" - description "Mega Man Battle Network 4 - Red Sun (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 4 - Red Sun (Europe) (Virtual Console).gba" size 8388608 crc cb3bbf74 sha1 36d83a1509d28b0c09365466cc1481c919d84cb0 ) + name "Megaman - Battle Network 5 - Team Colonel (Europe)" + description "Megaman - Battle Network 5 - Team Colonel (Europe)" + rom ( name "Megaman - Battle Network 5 - Team Colonel (Europe).gba" size 8388608 crc 8fc8cf73 sha1 d15bcb7c351252a8890c29a2eaac25ff621635c9 ) ) game ( - name "Mega Man Battle Network 4 - Red Sun (USA)" - description "Mega Man Battle Network 4 - Red Sun (USA)" - rom ( name "Mega Man Battle Network 4 - Red Sun (USA).gba" size 8388608 crc 2120695c sha1 a97e96a7da03abd70f7953328e511b9fa29179f1 ) + name "Megaman - Battle Network 5 - Team Colonel (USA)" + description "Megaman - Battle Network 5 - Team Colonel (USA)" + rom ( name "Megaman - Battle Network 5 - Team Colonel (USA).gba" size 8388608 crc a552f683 sha1 5f472f78d8de2df01d5039e045c043cb40969a39 ) ) game ( - name "Mega Man Battle Network 4 - Red Sun (Europe)" - description "Mega Man Battle Network 4 - Red Sun (Europe)" - rom ( name "Mega Man Battle Network 4 - Red Sun (Europe).gba" size 8388608 crc 0cb136c2 sha1 21af9f7805a27729e770928f939acedd6ae27c1c ) + name "Megaman - Battle Network 5 - Team Colonel (Europe) (Virtual Console)" + description "Megaman - Battle Network 5 - Team Colonel (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 5 - Team Colonel (Europe) (Virtual Console).gba" size 8388608 crc 5247772c sha1 061c291b29629d5ce44011d2d83931f2e35044ed ) ) game ( - name "Mega Man Battle Network 5 - Team Colonel (Europe)" - description "Mega Man Battle Network 5 - Team Colonel (Europe)" - rom ( name "Mega Man Battle Network 5 - Team Colonel (Europe).gba" size 8388608 crc 8fc8cf73 sha1 d15bcb7c351252a8890c29a2eaac25ff621635c9 ) + name "Megaman - Battle Network 5 - Team Protoman (Europe)" + description "Megaman - Battle Network 5 - Team Protoman (Europe)" + rom ( name "Megaman - Battle Network 5 - Team Protoman (Europe).gba" size 8388608 crc 79f45ed8 sha1 3d017ed23535e42174299ff89fff44678eb553c3 ) ) game ( - name "Mega Man Battle Network 5 - Team Colonel (USA)" - description "Mega Man Battle Network 5 - Team Colonel (USA)" - rom ( name "Mega Man Battle Network 5 - Team Colonel (USA).gba" size 8388608 crc a552f683 sha1 5f472f78d8de2df01d5039e045c043cb40969a39 ) + name "Megaman - Battle Network 5 - Team Protoman (USA)" + description "Megaman - Battle Network 5 - Team Protoman (USA)" + rom ( name "Megaman - Battle Network 5 - Team Protoman (USA).gba" size 8388608 crc a73e83a4 sha1 b3774e96b1f107bb8b1db79b216be41b9bc5bac0 ) ) game ( - name "Mega Man Battle Network 5 - Team Colonel (Europe) (Virtual Console)" - description "Mega Man Battle Network 5 - Team Colonel (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 5 - Team Colonel (Europe) (Virtual Console).gba" size 8388608 crc 5247772c sha1 061c291b29629d5ce44011d2d83931f2e35044ed ) + name "Megaman - Battle Network 5 - Team Protoman (USA) (Virtual Console)" + description "Megaman - Battle Network 5 - Team Protoman (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 5 - Team Protoman (USA) (Virtual Console).gba" size 8388608 crc a0911541 sha1 70ee16615f7d9d6bb13382d70dd2f213b918063b ) ) game ( - name "Mega Man Battle Network 5 - Team Colonel (USA) (Virtual Console)" - description "Mega Man Battle Network 5 - Team Colonel (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 5 - Team Colonel (USA) (Virtual Console).gba" size 8388608 crc 78dd4edc sha1 c715f1d01e016ad6890ebc8ec90120bc3b146a7e ) + name "Megaman - Battle Network 5 - Team Protoman (Europe) (Virtual Console)" + description "Megaman - Battle Network 5 - Team Protoman (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 5 - Team Protoman (Europe) (Virtual Console).gba" size 8388608 crc 7e5bc83d sha1 b68b310e3106e7fa6a47d4155239be2e43959da4 ) ) game ( - name "Mega Man Battle Network 5 - Team Proto Man (USA) (Virtual Console)" - description "Mega Man Battle Network 5 - Team Proto Man (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 5 - Team Proto Man (USA) (Virtual Console).gba" size 8388608 crc a0911541 sha1 70ee16615f7d9d6bb13382d70dd2f213b918063b ) + name "Megaman - Battle Network 6 - Cybeast Falzar (Europe)" + description "Megaman - Battle Network 6 - Cybeast Falzar (Europe)" + rom ( name "Megaman - Battle Network 6 - Cybeast Falzar (Europe).gba" size 8388608 crc 13183967 sha1 1f3037b33878fc66b79b4e2dcf1bb83202fa1b90 ) ) game ( - name "Mega Man Battle Network 5 - Team Proto Man (Europe) (Virtual Console)" - description "Mega Man Battle Network 5 - Team Proto Man (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 5 - Team Proto Man (Europe) (Virtual Console).gba" size 8388608 crc 7e5bc83d sha1 b68b310e3106e7fa6a47d4155239be2e43959da4 ) + name "Megaman - Battle Network 6 - Cybeast Falzar (USA)" + description "Megaman - Battle Network 6 - Cybeast Falzar (USA)" + rom ( name "Megaman - Battle Network 6 - Cybeast Falzar (USA).gba" size 8388608 crc dee6f2a9 sha1 0676ecd4d58a976af3346caebb44b9b6489ad099 flags verified ) ) game ( - name "Mega Man Battle Network 5 - Team Protoman (Europe)" - description "Mega Man Battle Network 5 - Team Protoman (Europe)" - rom ( name "Mega Man Battle Network 5 - Team Protoman (Europe).gba" size 8388608 crc 79f45ed8 sha1 3d017ed23535e42174299ff89fff44678eb553c3 ) + name "Megaman - Battle Network 6 - Cybeast Falzar (USA) (Virtual Console)" + description "Megaman - Battle Network 6 - Cybeast Falzar (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 6 - Cybeast Falzar (USA) (Virtual Console).gba" size 16777216 crc c2a21be3 sha1 c477367c5c9b81cbca2f3ba0cf6a820d489a3b7e ) ) game ( - name "Mega Man Battle Network 5 - Team Protoman (USA)" - description "Mega Man Battle Network 5 - Team Protoman (USA)" - rom ( name "Mega Man Battle Network 5 - Team Protoman (USA).gba" size 8388608 crc a73e83a4 sha1 b3774e96b1f107bb8b1db79b216be41b9bc5bac0 ) + name "Megaman - Battle Network 6 - Cybeast Falzar (Europe) (Virtual Console)" + description "Megaman - Battle Network 6 - Cybeast Falzar (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 6 - Cybeast Falzar (Europe) (Virtual Console).gba" size 16777216 crc 8104e85a sha1 e2dbec1cb65065ed716fa9851237677efe27ae1c ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Falzar (Europe)" - description "Mega Man Battle Network 6 - Cybeast Falzar (Europe)" - rom ( name "Mega Man Battle Network 6 - Cybeast Falzar (Europe).gba" size 8388608 crc 13183967 sha1 1f3037b33878fc66b79b4e2dcf1bb83202fa1b90 ) + name "Megaman - Battle Network 6 - Cybeast Gregar (USA)" + description "Megaman - Battle Network 6 - Cybeast Gregar (USA)" + rom ( name "Megaman - Battle Network 6 - Cybeast Gregar (USA).gba" size 8388608 crc 79452182 sha1 89fe0bac4fd3d2ab1d2ca35e87ef8b1294a84cd6 ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Falzar (USA)" - description "Mega Man Battle Network 6 - Cybeast Falzar (USA)" - rom ( name "Mega Man Battle Network 6 - Cybeast Falzar (USA).gba" size 8388608 crc dee6f2a9 sha1 0676ecd4d58a976af3346caebb44b9b6489ad099 flags verified ) + name "Megaman - Battle Network 6 - Cybeast Gregar (Europe)" + description "Megaman - Battle Network 6 - Cybeast Gregar (Europe)" + rom ( name "Megaman - Battle Network 6 - Cybeast Gregar (Europe).gba" size 8388608 crc 25c29efb sha1 4d2e441b1bcb8438c0bef2ae61d937de7d04af02 ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Falzar (USA) (Virtual Console)" - description "Mega Man Battle Network 6 - Cybeast Falzar (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 6 - Cybeast Falzar (USA) (Virtual Console).gba" size 16777216 crc c2a21be3 sha1 c477367c5c9b81cbca2f3ba0cf6a820d489a3b7e ) + name "Megaman - Battle Network 6 - Cybeast Gregar (USA) (Virtual Console)" + description "Megaman - Battle Network 6 - Cybeast Gregar (USA) (Virtual Console)" + rom ( name "Megaman - Battle Network 6 - Cybeast Gregar (USA) (Virtual Console).gba" size 8388608 crc e7e546fe sha1 0a8de8417b9939573daa04f95cdecdeaaf58a79e ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Falzar (Europe) (Virtual Console)" - description "Mega Man Battle Network 6 - Cybeast Falzar (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 6 - Cybeast Falzar (Europe) (Virtual Console).gba" size 16777216 crc 8104e85a sha1 e2dbec1cb65065ed716fa9851237677efe27ae1c ) + name "Megaman - Battle Network 6 - Cybeast Gregar (Europe) (Virtual Console)" + description "Megaman - Battle Network 6 - Cybeast Gregar (Europe) (Virtual Console)" + rom ( name "Megaman - Battle Network 6 - Cybeast Gregar (Europe) (Virtual Console).gba" size 8388608 crc bb62f987 sha1 7106dc0469898cb5768ec76c99029b24039d7605 ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Gregar (Europe) (Virtual Console)" - description "Mega Man Battle Network 6 - Cybeast Gregar (Europe) (Virtual Console)" - rom ( name "Mega Man Battle Network 6 - Cybeast Gregar (Europe) (Virtual Console).gba" size 8388608 crc bb62f987 sha1 7106dc0469898cb5768ec76c99029b24039d7605 ) + name "Megaman & Bass (USA) (Virtual Console)" + description "Megaman & Bass (USA) (Virtual Console)" + rom ( name "Megaman & Bass (USA) (Virtual Console).gba" size 8388608 crc b61f99d4 sha1 37db963a52aecec8018057cef3811860c3e889ed ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Gregar (USA)" - description "Mega Man Battle Network 6 - Cybeast Gregar (USA)" - rom ( name "Mega Man Battle Network 6 - Cybeast Gregar (USA).gba" size 8388608 crc 79452182 sha1 89fe0bac4fd3d2ab1d2ca35e87ef8b1294a84cd6 ) + name "Megaman & Bass (Europe)" + description "Megaman & Bass (Europe)" + rom ( name "Megaman & Bass (Europe).gba" size 8388608 crc 01b4d95e sha1 5d6f8fb1f52803a54e9857e53d0b88173cf8f48a flags verified ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Gregar (Europe)" - description "Mega Man Battle Network 6 - Cybeast Gregar (Europe)" - rom ( name "Mega Man Battle Network 6 - Cybeast Gregar (Europe).gba" size 8388608 crc 25c29efb sha1 4d2e441b1bcb8438c0bef2ae61d937de7d04af02 ) + name "Megaman & Bass (Europe) (Virtual Console)" + description "Megaman & Bass (Europe) (Virtual Console)" + rom ( name "Megaman & Bass (Europe) (Virtual Console).gba" size 8388608 crc 6e140bfa sha1 37a188a250ff553a71144f8bbe92098c85c8006d ) ) game ( - name "Mega Man Battle Network 6 - Cybeast Gregar (USA) (Virtual Console)" - description "Mega Man Battle Network 6 - Cybeast Gregar (USA) (Virtual Console)" - rom ( name "Mega Man Battle Network 6 - Cybeast Gregar (USA) (Virtual Console).gba" size 8388608 crc e7e546fe sha1 0a8de8417b9939573daa04f95cdecdeaaf58a79e ) + name "Megaman & Bass (USA)" + description "Megaman & Bass (USA)" + rom ( name "Megaman & Bass (USA).gba" size 8388608 crc eea68c2e sha1 7610847b331870d4338e5ac894b36e55e2bec5a0 flags verified ) ) game ( - name "Mega Man Zero (USA) (Virtual Console)" - description "Mega Man Zero (USA) (Virtual Console)" - rom ( name "Mega Man Zero (USA) (Virtual Console).gba" size 8388608 crc 9c77209c sha1 7279705e24d32895dada7f5476f68bbc33dd643b ) + name "Megaman Zero (USA, Europe)" + description "Megaman Zero (USA, Europe)" + rom ( name "Megaman Zero (USA, Europe).gba" size 8388608 crc 9707d2a1 sha1 193b14120119162518a73c70876f0b8bffdbd96e flags verified ) ) game ( - name "Mega Man Zero (USA, Europe)" - description "Mega Man Zero (USA, Europe)" - rom ( name "Mega Man Zero (USA, Europe).gba" size 8388608 crc 9707d2a1 sha1 193b14120119162518a73c70876f0b8bffdbd96e flags verified ) + name "Megaman Zero (USA) (Virtual Console)" + description "Megaman Zero (USA) (Virtual Console)" + rom ( name "Megaman Zero (USA) (Virtual Console).gba" size 8388608 crc 9c77209c sha1 7279705e24d32895dada7f5476f68bbc33dd643b ) ) game ( - name "Mega Man Zero 2 (USA) (Virtual Console)" - description "Mega Man Zero 2 (USA) (Virtual Console)" - rom ( name "Mega Man Zero 2 (USA) (Virtual Console).gba" size 8388608 crc 30d051fe sha1 d7a1edd912f8e01bc442809b922bceaf5a1f0176 ) + name "Megaman Zero 2 (USA) (Virtual Console)" + description "Megaman Zero 2 (USA) (Virtual Console)" + rom ( name "Megaman Zero 2 (USA) (Virtual Console).gba" size 8388608 crc 30d051fe sha1 d7a1edd912f8e01bc442809b922bceaf5a1f0176 ) ) game ( - name "Mega Man Zero 2 (USA)" - description "Mega Man Zero 2 (USA)" - rom ( name "Mega Man Zero 2 (USA).gba" size 8388608 crc ce1e37bb sha1 c4d93a58f0f82c526dec8a3fdbda170336303689 ) + name "Megaman Zero 2 (USA)" + description "Megaman Zero 2 (USA)" + rom ( name "Megaman Zero 2 (USA).gba" size 8388608 crc ce1e37bb sha1 c4d93a58f0f82c526dec8a3fdbda170336303689 ) ) game ( - name "Mega Man Zero 2 (Europe)" - description "Mega Man Zero 2 (Europe)" - rom ( name "Mega Man Zero 2 (Europe).gba" size 8388608 crc 29a14b59 sha1 c55eca8f2c31fdf772f2605181d0b29815ea37a0 ) + name "Megaman Zero 2 (Europe)" + description "Megaman Zero 2 (Europe)" + rom ( name "Megaman Zero 2 (Europe).gba" size 8388608 crc 29a14b59 sha1 c55eca8f2c31fdf772f2605181d0b29815ea37a0 ) ) game ( - name "Mega Man Zero 2 (Europe) (Virtual Console)" - description "Mega Man Zero 2 (Europe) (Virtual Console)" - rom ( name "Mega Man Zero 2 (Europe) (Virtual Console).gba" size 8388608 crc d76f2d1c sha1 4ae9cd23f80d190f21002d2fdf4b8847c9452592 ) + name "Megaman Zero 2 (Europe) (Virtual Console)" + description "Megaman Zero 2 (Europe) (Virtual Console)" + rom ( name "Megaman Zero 2 (Europe) (Virtual Console).gba" size 8388608 crc d76f2d1c sha1 4ae9cd23f80d190f21002d2fdf4b8847c9452592 ) ) game ( - name "Mega Man Zero 3 (Europe) (Virtual Console)" - description "Mega Man Zero 3 (Europe) (Virtual Console)" - rom ( name "Mega Man Zero 3 (Europe) (Virtual Console).gba" size 8388608 crc 87e8656e sha1 8245ecb895caf0e0a2914f46bb79e4c9c5ba8c4a ) + name "Megaman Zero 3 (Europe) (Virtual Console)" + description "Megaman Zero 3 (Europe) (Virtual Console)" + rom ( name "Megaman Zero 3 (Europe) (Virtual Console).gba" size 8388608 crc 87e8656e sha1 8245ecb895caf0e0a2914f46bb79e4c9c5ba8c4a ) ) game ( - name "Mega Man Zero 3 (USA) (Virtual Console)" - description "Mega Man Zero 3 (USA) (Virtual Console)" - rom ( name "Mega Man Zero 3 (USA) (Virtual Console).gba" size 16777216 crc cbd24ac4 sha1 de5413481d823c53973cb29507567ef3dc6af399 ) + name "Megaman Zero 3 (USA) (Virtual Console)" + description "Megaman Zero 3 (USA) (Virtual Console)" + rom ( name "Megaman Zero 3 (USA) (Virtual Console).gba" size 16777216 crc cbd24ac4 sha1 de5413481d823c53973cb29507567ef3dc6af399 ) ) game ( - name "Mega Man Zero 3 (Europe)" - description "Mega Man Zero 3 (Europe)" - rom ( name "Mega Man Zero 3 (Europe).gba" size 8388608 crc b099577f sha1 edfcb606136951374f24aa8fd7e5b4e710300301 ) + name "Megaman Zero 3 (Europe)" + description "Megaman Zero 3 (Europe)" + rom ( name "Megaman Zero 3 (Europe).gba" size 8388608 crc b099577f sha1 edfcb606136951374f24aa8fd7e5b4e710300301 ) ) game ( - name "Mega Man Zero 3 (USA)" - description "Mega Man Zero 3 (USA)" - rom ( name "Mega Man Zero 3 (USA).gba" size 8388608 crc 2784f3f2 sha1 403a78f2cad93d41e4b0f2e520ce08026531664b ) + name "Megaman Zero 3 (USA)" + description "Megaman Zero 3 (USA)" + rom ( name "Megaman Zero 3 (USA).gba" size 8388608 crc 2784f3f2 sha1 403a78f2cad93d41e4b0f2e520ce08026531664b ) ) game ( - name "Mega Man Zero 4 (Europe) (Virtual Console)" - description "Mega Man Zero 4 (Europe) (Virtual Console)" - rom ( name "Mega Man Zero 4 (Europe) (Virtual Console).gba" size 16777216 crc ffda95be sha1 4424f9e08381a447192d87bbad20dab3c77740db ) + name "Megaman Zero 4 (Europe) (Virtual Console)" + description "Megaman Zero 4 (Europe) (Virtual Console)" + rom ( name "Megaman Zero 4 (Europe) (Virtual Console).gba" size 16777216 crc ffda95be sha1 4424f9e08381a447192d87bbad20dab3c77740db ) ) game ( - name "Mega Man Zero 4 (Europe)" - description "Mega Man Zero 4 (Europe)" - rom ( name "Mega Man Zero 4 (Europe).gba" size 16777216 crc b7f022b9 sha1 8e13b9ee89a2ed665212daa401ba9331ad11bda9 ) + name "Megaman Zero 4 (Europe)" + description "Megaman Zero 4 (Europe)" + rom ( name "Megaman Zero 4 (Europe).gba" size 16777216 crc b7f022b9 sha1 8e13b9ee89a2ed665212daa401ba9331ad11bda9 ) ) game ( - name "Mega Man Zero 4 (USA)" - description "Mega Man Zero 4 (USA)" - rom ( name "Mega Man Zero 4 (USA).gba" size 16777216 crc 7ee24793 sha1 596993205a1895a6f51e80749407fb069b907628 ) + name "Megaman Zero 4 (USA)" + description "Megaman Zero 4 (USA)" + rom ( name "Megaman Zero 4 (USA).gba" size 16777216 crc 7ee24793 sha1 596993205a1895a6f51e80749407fb069b907628 ) ) game ( - name "Mega Man Zero 4 (USA) (Virtual Console)" - description "Mega Man Zero 4 (USA) (Virtual Console)" - rom ( name "Mega Man Zero 4 (USA) (Virtual Console).gba" size 16777216 crc c4838cfa sha1 24a774446c8f652c78bb4bd938fc57c612db3d6c flags verified ) + name "Megaman Zero 4 (USA) (Virtual Console)" + description "Megaman Zero 4 (USA) (Virtual Console)" + rom ( name "Megaman Zero 4 (USA) (Virtual Console).gba" size 16777216 crc c4838cfa sha1 24a774446c8f652c78bb4bd938fc57c612db3d6c flags verified ) ) game ( @@ -11460,6 +11826,12 @@ game ( rom ( name "Metal Slug Advance (Europe).gba" size 8388608 crc 3806f4ae sha1 0719aee29b0da365e7ad52bb0ae9545bcd377152 flags verified ) ) +game ( + name "Metal Warrior 4 (World) (v1.3) (Aftermarket) (Unl)" + description "Metal Warrior 4 (World) (v1.3) (Aftermarket) (Unl)" + rom ( name "Metal Warrior 4 (World) (v1.3) (Aftermarket) (Unl).gba" size 524288 crc 7ec3485e sha1 729592141bc160ead0af51d4322c7f9f17da0b82 ) +) + game ( name "Metalgun Slinger (Japan)" description "Metalgun Slinger (Japan)" @@ -11467,21 +11839,9 @@ game ( ) game ( - name "Metroid - Zero Mission (USA)" - description "Metroid - Zero Mission (USA)" - rom ( name "Metroid - Zero Mission (USA).gba" size 8388608 crc 5c61a844 sha1 5de8536afe1f0078ee6fe1089f890e8c7aa0a6e8 flags verified ) -) - -game ( - name "Metroid - Zero Mission (Europe) (En,Fr,De,Es,It)" - description "Metroid - Zero Mission (Europe) (En,Fr,De,Es,It)" - rom ( name "Metroid - Zero Mission (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc f1d92e63 sha1 0fd107445a42e6f3a3e5ce8c865f412583179903 flags verified ) -) - -game ( - name "Metroid - Zero Mission (Japan)" - description "Metroid - Zero Mission (Japan)" - rom ( name "Metroid - Zero Mission (Japan).gba" size 8388608 crc 44b79e2b sha1 096f07685a3dc9286e71aa0b761f233b5efa2fcd ) + name "Metroid - Zero Mission (Japan) (Virtual Console)" + description "Metroid - Zero Mission (Japan) (Virtual Console)" + rom ( name "Metroid - Zero Mission (Japan) (Virtual Console).gba" size 8388608 crc 220b68f5 sha1 24d99f32875464dbcef5ca8ec231ec42073ff1e8 ) ) game ( @@ -11509,9 +11869,21 @@ game ( ) game ( - name "Metroid - Zero Mission (Japan) (Virtual Console)" - description "Metroid - Zero Mission (Japan) (Virtual Console)" - rom ( name "Metroid - Zero Mission (Japan) (Virtual Console).gba" size 8388608 crc 220b68f5 sha1 24d99f32875464dbcef5ca8ec231ec42073ff1e8 ) + name "Metroid - Zero Mission (USA)" + description "Metroid - Zero Mission (USA)" + rom ( name "Metroid - Zero Mission (USA).gba" size 8388608 crc 5c61a844 sha1 5de8536afe1f0078ee6fe1089f890e8c7aa0a6e8 flags verified ) +) + +game ( + name "Metroid - Zero Mission (Europe) (En,Fr,De,Es,It)" + description "Metroid - Zero Mission (Europe) (En,Fr,De,Es,It)" + rom ( name "Metroid - Zero Mission (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc f1d92e63 sha1 0fd107445a42e6f3a3e5ce8c865f412583179903 flags verified ) +) + +game ( + name "Metroid - Zero Mission (Japan)" + description "Metroid - Zero Mission (Japan)" + rom ( name "Metroid - Zero Mission (Japan).gba" size 8388608 crc 44b79e2b sha1 096f07685a3dc9286e71aa0b761f233b5efa2fcd ) ) game ( @@ -11664,6 +12036,24 @@ game ( rom ( name "Mini Moni. - Onegai Ohoshi-sama! (Japan).gba" size 8388608 crc f11c35cc sha1 d34795cf3679c6f259177db52a138c0d6e9fcdfd ) ) +game ( + name "Minicraft (World) (v1.0) (Aftermarket) (Unl)" + description "Minicraft (World) (v1.0) (Aftermarket) (Unl)" + rom ( name "Minicraft (World) (v1.0) (Aftermarket) (Unl).gba" size 131072 crc e852c9e9 sha1 06faa5be11978666db6995d8fce40ce2c3641ce8 ) +) + +game ( + name "Minicraft (World) (v1.1) (Aftermarket) (Unl)" + description "Minicraft (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Minicraft (World) (v1.1) (Aftermarket) (Unl).gba" size 131072 crc 07595773 sha1 fee5cfa5b9e1f3383780432772f29764ac0fc443 ) +) + +game ( + name "Minicraft (World) (v1.2) (Aftermarket) (Unl)" + description "Minicraft (World) (v1.2) (Aftermarket) (Unl)" + rom ( name "Minicraft (World) (v1.2) (Aftermarket) (Unl).gba" size 131072 crc 37e7ee7d sha1 dc7faa4952986d5c5f0e3b32203936cd717f97eb ) +) + game ( name "Minna de Puyo Puyo (Japan) (En,Ja)" description "Minna de Puyo Puyo (Japan) (En,Ja)" @@ -11773,9 +12163,9 @@ game ( ) game ( - name "Misfortune Advance (World) (Aftermarket) (Homebrew)" - description "Misfortune Advance (World) (Aftermarket) (Homebrew)" - rom ( name "Misfortune Advance (World) (Aftermarket) (Homebrew).gba" size 5125100 crc 18f2166d sha1 68e215025ac963220f16ea3c100e51698f97c4eb ) + name "Misfortune Advance (World) (Aftermarket) (Unl)" + description "Misfortune Advance (World) (Aftermarket) (Unl)" + rom ( name "Misfortune Advance (World) (Aftermarket) (Unl).gba" size 5125100 crc 18f2166d sha1 68e215025ac963220f16ea3c100e51698f97c4eb ) ) game ( @@ -11803,15 +12193,9 @@ game ( ) game ( - name "MLB SlugFest 20-04 (USA)" - description "MLB SlugFest 20-04 (USA)" - rom ( name "MLB SlugFest 20-04 (USA).gba" size 4194304 crc a4e12d4b sha1 cd60f0aacdada987f7935d7a5fa2cd3242abc145 ) -) - -game ( - name "Mo Jie Qibing (Taiwan) (Unl)" - description "Mo Jie Qibing (Taiwan) (Unl)" - rom ( name "Mo Jie Qibing (Taiwan) (Unl).gba" size 4194304 crc 8ee0ed6f sha1 e9b68e1f7584892b366a6a4b3a94feeb8729e4c5 ) + name "MLB SlugFest 2004 (USA)" + description "MLB SlugFest 2004 (USA)" + rom ( name "MLB SlugFest 2004 (USA).gba" size 4194304 crc a4e12d4b sha1 cd60f0aacdada987f7935d7a5fa2cd3242abc145 ) ) game ( @@ -11832,6 +12216,12 @@ game ( rom ( name "Moero!! Jaleco Collection (Japan).gba" size 4194304 crc 6da36e82 sha1 52d1cbeed52de62147d13a667a9631f6d8a24865 ) ) +game ( + name "Mojie Qibing (Taiwan) (Unl)" + description "Mojie Qibing (Taiwan) (Unl)" + rom ( name "Mojie Qibing (Taiwan) (Unl).gba" size 4194304 crc 8ee0ed6f sha1 e9b68e1f7584892b366a6a4b3a94feeb8729e4c5 ) +) + game ( name "Momotarou Dentetsu G - Gold Deck o Tsukure! (Japan)" description "Momotarou Dentetsu G - Gold Deck o Tsukure! (Japan)" @@ -12030,12 +12420,30 @@ game ( rom ( name "Monsters, Inc. (Europe) (En,Es,Nl).gba" size 4194304 crc d13177e0 sha1 36645b8de074f0b27dbe61528e70ae3af28fb3b9 ) ) +game ( + name "Mooncat's Trio (World) (Aftermarket) (Unl)" + description "Mooncat's Trio (World) (Aftermarket) (Unl)" + rom ( name "Mooncat's Trio (World) (Aftermarket) (Unl).gba" size 1175680 crc b05d5339 sha1 890de7d73723d235d9762e4866d569d3554d1480 flags verified ) +) + +game ( + name "Mooncat's Trio (World) (Beta) (Aftermarket) (Unl)" + description "Mooncat's Trio (World) (Beta) (Aftermarket) (Unl)" + rom ( name "Mooncat's Trio (World) (Beta) (Aftermarket) (Unl).gba" size 504220 crc cd3328ee sha1 c3ea5247f32c428bbcfd5c087218fc56779e3106 ) +) + game ( name "Moorhen 3 - The Chicken Chase! (Europe) (En,Fr,De,Es,It)" description "Moorhen 3 - The Chicken Chase! (Europe) (En,Fr,De,Es,It)" rom ( name "Moorhen 3 - The Chicken Chase! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc a16c10a8 sha1 b743dd4b3f1bfa169fed64f86766d5a616c5ee60 ) ) +game ( + name "Moorhuhn Jagd (Europe) (Proto)" + description "Moorhuhn Jagd (Europe) (Proto)" + rom ( name "Moorhuhn Jagd (Europe) (Proto).gba" size 8388608 crc d3f841f3 sha1 a2a698345251b9487c5387a665b8c49c3af7ccd5 ) +) + game ( name "Morita Shougi Advance (Japan)" description "Morita Shougi Advance (Japan)" @@ -12096,6 +12504,18 @@ game ( rom ( name "Mother 3 (Japan) (Virtual Console).gba" size 33554432 crc c704a567 sha1 a9fb9c36df3b0fb24b266826f5853c56122f9d36 ) ) +game ( + name "Moto Racer Advance (USA) (En,Fr,De,Es,It)" + description "Moto Racer Advance (USA) (En,Fr,De,Es,It)" + rom ( name "Moto Racer Advance (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 2fdbe7a8 sha1 351414650e6969c270b1339ada7b3565ce80374c ) +) + +game ( + name "Moto Racer Advance (Europe) (En,Fr,De,Es,It)" + description "Moto Racer Advance (Europe) (En,Fr,De,Es,It)" + rom ( name "Moto Racer Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 8cb19da0 sha1 b91bad8ee04652d71e0610f8d1a5deaebd4c1fd0 flags verified ) +) + game ( name "Motocross Challenge (USA) (Proto)" description "Motocross Challenge (USA) (Proto)" @@ -12138,18 +12558,6 @@ game ( rom ( name "MotoGP (Europe) (Beta).gba" size 4194304 crc 508bf8dc sha1 25554ecf8c3b534e0a70c6d4e402fa8f721da7d8 ) ) -game ( - name "Motoracer Advance (USA) (En,Fr,De,Es,It)" - description "Motoracer Advance (USA) (En,Fr,De,Es,It)" - rom ( name "Motoracer Advance (USA) (En,Fr,De,Es,It).gba" size 4194304 crc 2fdbe7a8 sha1 351414650e6969c270b1339ada7b3565ce80374c ) -) - -game ( - name "Motoracer Advance (Europe) (En,Fr,De,Es,It)" - description "Motoracer Advance (Europe) (En,Fr,De,Es,It)" - rom ( name "Motoracer Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 8cb19da0 sha1 b91bad8ee04652d71e0610f8d1a5deaebd4c1fd0 flags verified ) -) - game ( name "Mr Nutz (Europe) (En,Fr,De,Es,It)" description "Mr Nutz (Europe) (En,Fr,De,Es,It)" @@ -12168,12 +12576,6 @@ game ( rom ( name "Mr. Driller 2 (USA).gba" size 4194304 crc 02f51696 sha1 e7009dd8418303343c4aac2558538b8caa28b694 ) ) -game ( - name "Mr. Driller 2 (Japan)" - description "Mr. Driller 2 (Japan)" - rom ( name "Mr. Driller 2 (Japan).gba" size 4194304 crc 5264c730 sha1 0373318ef431b1d02708941af261c91de1677d9d ) -) - game ( name "Mr. Driller 2 (USA) (Virtual Console)" description "Mr. Driller 2 (USA) (Virtual Console)" @@ -12193,9 +12595,9 @@ game ( ) game ( - name "Mr. Driller A - Fushigi na Pacteria (Japan) (Virtual Console)" - description "Mr. Driller A - Fushigi na Pacteria (Japan) (Virtual Console)" - rom ( name "Mr. Driller A - Fushigi na Pacteria (Japan) (Virtual Console).gba" size 8388608 crc 5f595157 sha1 d51a4ef35205cb61a242db65be6a7807d49dec5c ) + name "Mr. Driller 2 (Japan)" + description "Mr. Driller 2 (Japan)" + rom ( name "Mr. Driller 2 (Japan).gba" size 4194304 crc 5264c730 sha1 0373318ef431b1d02708941af261c91de1677d9d ) ) game ( @@ -12204,6 +12606,12 @@ game ( rom ( name "Mr. Driller A - Fushigi na Pacteria (Japan).gba" size 8388608 crc 529f06a4 sha1 ccfb5f3051b4d3bdec38f0085f2a585ecf249f20 ) ) +game ( + name "Mr. Driller A - Fushigi na Pacteria (Japan) (Virtual Console)" + description "Mr. Driller A - Fushigi na Pacteria (Japan) (Virtual Console)" + rom ( name "Mr. Driller A - Fushigi na Pacteria (Japan) (Virtual Console).gba" size 8388608 crc 5f595157 sha1 d51a4ef35205cb61a242db65be6a7807d49dec5c ) +) + game ( name "Mr. Incredible (Japan)" description "Mr. Incredible (Japan)" @@ -12342,6 +12750,12 @@ game ( rom ( name "Nakayoshi Pet Advance Series 4 - Kawaii Koinu Mini - Wanko to Asobou!! Kogata-ken (Japan).gba" size 4194304 crc ae2a69f3 sha1 0c78a24d5a8a296d05a8b47cf5623de0f031748e ) ) +game ( + name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan)" + description "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan)" + rom ( name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan).gba" size 4194304 crc 1276a95c sha1 77743de7541e0a9d09e3aac864c4e3f9f1a51d2b ) +) + game ( name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan) (Rev 1)" description "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan) (Rev 1)" @@ -12349,9 +12763,9 @@ game ( ) game ( - name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan)" - description "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan)" - rom ( name "Nakayoshi Youchien - Sukoyaka Enji Ikusei Game (Japan).gba" size 4194304 crc 1276a95c sha1 77743de7541e0a9d09e3aac864c4e3f9f1a51d2b ) + name "Namco Museum (Europe)" + description "Namco Museum (Europe)" + rom ( name "Namco Museum (Europe).gba" size 4194304 crc bb82460a sha1 3e84508a0d2362a0abf31dede1d55b865566213c ) ) game ( @@ -12366,12 +12780,6 @@ game ( rom ( name "Namco Museum (Japan) (En).gba" size 4194304 crc 818f4e4b sha1 54d01cf5ac57f5fb454c0e188de9e60f63854a97 ) ) -game ( - name "Namco Museum (Europe)" - description "Namco Museum (Europe)" - rom ( name "Namco Museum (Europe).gba" size 4194304 crc bb82460a sha1 3e84508a0d2362a0abf31dede1d55b865566213c ) -) - game ( name "Namco Museum - 50th Anniversary (USA)" description "Namco Museum - 50th Anniversary (USA)" @@ -12492,6 +12900,12 @@ game ( rom ( name "NBA Jam 2002 (USA, Europe).gba" size 4194304 crc ca428a7a sha1 38de98758669b120b895661bec3882c3474cf47e ) ) +game ( + name "Need for Speed - Carbon - Own the City (USA, Europe) (En,Fr,De,Es,It)" + description "Need for Speed - Carbon - Own the City (USA, Europe) (En,Fr,De,Es,It)" + rom ( name "Need for Speed - Carbon - Own the City (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc f4c0d140 sha1 e5298b2482a769aa6458955cd6b18db3ac3f3a20 flags verified ) +) + game ( name "Need for Speed - Most Wanted (USA, Europe) (En,Fr,De,It)" description "Need for Speed - Most Wanted (USA, Europe) (En,Fr,De,It)" @@ -12513,7 +12927,7 @@ game ( game ( name "Need for Speed - Underground (USA, Europe) (En,Fr,De,It)" description "Need for Speed - Underground (USA, Europe) (En,Fr,De,It)" - rom ( name "Need for Speed - Underground (USA, Europe) (En,Fr,De,It).gba" size 8388608 crc 828020e9 sha1 ddd304481617a748aa9f37535908a37452dd2f03 ) + rom ( name "Need for Speed - Underground (USA, Europe) (En,Fr,De,It).gba" size 8388608 crc 828020e9 sha1 ddd304481617a748aa9f37535908a37452dd2f03 flags verified ) ) game ( @@ -12522,12 +12936,6 @@ game ( rom ( name "Need for Speed - Underground 2 (USA, Europe) (En,Fr,De,It).gba" size 8388608 crc 9a0c5090 sha1 f772000fbdfb84d8d5de9f69bd9c0de551389929 flags verified ) ) -game ( - name "Need for Speed Carbon - Own the City (USA, Europe) (En,Fr,De,Es,It)" - description "Need for Speed Carbon - Own the City (USA, Europe) (En,Fr,De,Es,It)" - rom ( name "Need for Speed Carbon - Own the City (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc f4c0d140 sha1 e5298b2482a769aa6458955cd6b18db3ac3f3a20 flags verified ) -) - game ( name "Nekketsu Monogatari Advance (Japan) (Demo) (Aftermarket) (Unl)" description "Nekketsu Monogatari Advance (Japan) (Demo) (Aftermarket) (Unl)" @@ -12559,15 +12967,15 @@ game ( ) game ( - name "NFL Blitz 20-02 (USA)" - description "NFL Blitz 20-02 (USA)" - rom ( name "NFL Blitz 20-02 (USA).gba" size 4194304 crc 8c748dcb sha1 590196c49eb4b33d933db60d58a1d0efd94b3f7b ) + name "NFL Blitz 2002 (USA)" + description "NFL Blitz 2002 (USA)" + rom ( name "NFL Blitz 2002 (USA).gba" size 4194304 crc 8c748dcb sha1 590196c49eb4b33d933db60d58a1d0efd94b3f7b ) ) game ( - name "NFL Blitz 20-03 (USA)" - description "NFL Blitz 20-03 (USA)" - rom ( name "NFL Blitz 20-03 (USA).gba" size 4194304 crc e0b137e7 sha1 6d63871abf8016248ff7f8777d762e7c75877d40 ) + name "NFL Blitz 2003 (USA)" + description "NFL Blitz 2003 (USA)" + rom ( name "NFL Blitz 2003 (USA).gba" size 4194304 crc e0b137e7 sha1 6d63871abf8016248ff7f8777d762e7c75877d40 ) ) game ( @@ -12577,9 +12985,9 @@ game ( ) game ( - name "NHL Hitz 20-03 (USA)" - description "NHL Hitz 20-03 (USA)" - rom ( name "NHL Hitz 20-03 (USA).gba" size 4194304 crc 4f1adf75 sha1 4a88ca2962fdfb7ea1b91b9e2bffe8c69ff96519 ) + name "NHL Hitz 2003 (USA)" + description "NHL Hitz 2003 (USA)" + rom ( name "NHL Hitz 2003 (USA).gba" size 4194304 crc 4f1adf75 sha1 4a88ca2962fdfb7ea1b91b9e2bffe8c69ff96519 ) ) game ( @@ -12645,7 +13053,7 @@ game ( game ( name "Nintendo MP3 Player (Europe) (En,Fr,De,Es,It)" description "Nintendo MP3 Player (Europe) (En,Fr,De,Es,It)" - rom ( name "Nintendo MP3 Player (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 867bec76 sha1 0c1eb4af684f3b428766b10cdbbe62fd726e5e27 ) + rom ( name "Nintendo MP3 Player (Europe) (En,Fr,De,Es,It).gba" size 1048576 crc 16e5d0f2 sha1 b7c517f1cb5860fec8beaa4e819bcffa8ce95a5b flags verified ) ) game ( @@ -12723,7 +13131,7 @@ game ( game ( name "Oddworld - Munch's Oddysee (USA, Europe)" description "Oddworld - Munch's Oddysee (USA, Europe)" - rom ( name "Oddworld - Munch's Oddysee (USA, Europe).gba" size 8388608 crc 97367887 sha1 cc6bf19e5d6a35c2a745bea4e3b2a210a9ebd296 flags verified ) + rom ( name "Oddworld - Munch's Oddysee (USA, Europe).gba" size 8388608 crc 97367887 sha1 cc6bf19e5d6a35c2a745bea4e3b2a210a9ebd296 ) ) game ( @@ -12853,9 +13261,9 @@ game ( ) game ( - name "Oshare Princess 2 (Japan)" - description "Oshare Princess 2 (Japan)" - rom ( name "Oshare Princess 2 (Japan).gba" size 8388608 crc 8383fcda sha1 649001f85cdcd2515183fc1364d08de52c918feb ) + name "Oshare Princess 2 + Doubutsu Kyaranabi Uranai (Japan)" + description "Oshare Princess 2 + Doubutsu Kyaranabi Uranai (Japan)" + rom ( name "Oshare Princess 2 + Doubutsu Kyaranabi Uranai (Japan).gba" size 8388608 crc 8383fcda sha1 649001f85cdcd2515183fc1364d08de52c918feb ) ) game ( @@ -12931,9 +13339,9 @@ game ( ) game ( - name "Overstorm (Unknown) (Proto)" - description "Overstorm (Unknown) (Proto)" - rom ( name "Overstorm (Unknown) (Proto).gba" size 3470916 crc ee764cf6 sha1 88129a07e9dfb556c38a5c61c6e96fbfb4d23fea ) + name "Overstorm (Europe) (Proto)" + description "Overstorm (Europe) (Proto)" + rom ( name "Overstorm (Europe) (Proto).gba" size 3470916 crc ee764cf6 sha1 88129a07e9dfb556c38a5c61c6e96fbfb4d23fea ) ) game ( @@ -13033,9 +13441,9 @@ game ( ) game ( - name "Pac-Man World 2 (USA) (Beta)" - description "Pac-Man World 2 (USA) (Beta)" - rom ( name "Pac-Man World 2 (USA) (Beta).gba" size 4194304 crc b645b5ef sha1 82fe986f205f733c29bc00cd96ddf3ec46098fc6 ) + name "Pac-Man World 2 (USA) (Beta) (2005-04-15)" + description "Pac-Man World 2 (USA) (Beta) (2005-04-15)" + rom ( name "Pac-Man World 2 (USA) (Beta) (2005-04-15).gba" size 4194304 crc b645b5ef sha1 82fe986f205f733c29bc00cd96ddf3ec46098fc6 ) ) game ( @@ -13153,9 +13561,9 @@ game ( ) game ( - name "Pferd & Pony 2 in 1 (Germany)" - description "Pferd & Pony 2 in 1 (Germany)" - rom ( name "Pferd & Pony 2 in 1 (Germany).gba" size 8388608 crc 965391ea sha1 ec0307c819b41ff0f3f5aa9212a6e333b2242675 ) + name "Pferd & Pony - Mein Pferdehof & Pferd and Pony - Lass Uns Reiten 2 (Germany)" + description "Pferd & Pony - Mein Pferdehof & Pferd and Pony - Lass Uns Reiten 2 (Germany)" + rom ( name "Pferd & Pony - Mein Pferdehof & Pferd and Pony - Lass Uns Reiten 2 (Germany).gba" size 8388608 crc 965391ea sha1 ec0307c819b41ff0f3f5aa9212a6e333b2242675 ) ) game ( @@ -13179,7 +13587,7 @@ game ( game ( name "Phantasy Star Collection (USA)" description "Phantasy Star Collection (USA)" - rom ( name "Phantasy Star Collection (USA).gba" size 8388608 crc e5a7fe17 sha1 9f2dc591c9b1526f9f965b1c375fb4ea7101fd16 ) + rom ( name "Phantasy Star Collection (USA).gba" size 8388608 crc e5a7fe17 sha1 9f2dc591c9b1526f9f965b1c375fb4ea7101fd16 flags verified ) ) game ( @@ -13266,6 +13674,12 @@ game ( rom ( name "Pinball Tycoon (USA).gba" size 4194304 crc 1c4d3fdf sha1 fac76a646d112a775f9877b53f1386716d968a79 ) ) +game ( + name "Ping-Pong Diplomacy Advance (World) (Aftermarket) (Unl)" + description "Ping-Pong Diplomacy Advance (World) (Aftermarket) (Unl)" + rom ( name "Ping-Pong Diplomacy Advance (World) (Aftermarket) (Unl).gba" size 1048576 crc 9ec140d3 sha1 9e19e8f97e8619a4755c3ceb482fa3e2ad5a4529 ) +) + game ( name "Pink Panther - Pinkadelic Pursuit (Europe) (En,Fr,De,Es,It)" description "Pink Panther - Pinkadelic Pursuit (Europe) (En,Fr,De,Es,It)" @@ -13323,13 +13737,13 @@ game ( game ( name "Pirates of the Caribbean - Dead Man's Chest (USA, Europe) (En,Fr,De,Es,It)" description "Pirates of the Caribbean - Dead Man's Chest (USA, Europe) (En,Fr,De,Es,It)" - rom ( name "Pirates of the Caribbean - Dead Man's Chest (USA, Europe) (En,Fr,De,Es,It).gba" size 16777216 crc d1a67be8 sha1 3a11c76edaad8fa0845b7da55e8ed26e26e09883 ) + rom ( name "Pirates of the Caribbean - Dead Man's Chest (USA, Europe) (En,Fr,De,Es,It).gba" size 16777216 crc d1a67be8 sha1 3a11c76edaad8fa0845b7da55e8ed26e26e09883 flags verified ) ) game ( name "Pirates of the Caribbean - The Curse of the Black Pearl (USA) (En,Fr,De,Es,It)" description "Pirates of the Caribbean - The Curse of the Black Pearl (USA) (En,Fr,De,Es,It)" - rom ( name "Pirates of the Caribbean - The Curse of the Black Pearl (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 8f15bf4c sha1 034e5206c3ed8275e4bbb249edf305d14948bf8f ) + rom ( name "Pirates of the Caribbean - The Curse of the Black Pearl (USA) (En,Fr,De,Es,It).gba" size 8388608 crc 8f15bf4c sha1 034e5206c3ed8275e4bbb249edf305d14948bf8f flags verified ) ) game ( @@ -13417,15 +13831,9 @@ game ( ) game ( - name "Pocket Monster Diamond Tomodachi to Issho Ni! Present Campaign Senyou Cartridge (Japan) [b]" - description "Pocket Monster Diamond Tomodachi to Issho Ni! Present Campaign Senyou Cartridge (Japan) [b]" - rom ( name "Pocket Monster Diamond Tomodachi to Issho Ni! Present Campaign Senyou Cartridge (Japan) [b].gba" size 2097152 crc 393a77e8 sha1 147d115e4d5d758ec386dce7b0063321a1dfd583 flags baddump ) -) - -game ( - name "Pocket Monster Pearl Tomodachi to Issho ni! Present Campaign Senyou Cartridge (Japan) [b]" - description "Pocket Monster Pearl Tomodachi to Issho ni! Present Campaign Senyou Cartridge (Japan) [b]" - rom ( name "Pocket Monster Pearl Tomodachi to Issho ni! Present Campaign Senyou Cartridge (Japan) [b].gba" size 2097152 crc 21e120be sha1 ebc831ef1e00e204975104cfbd0fd526e0f6e435 flags baddump ) + name "Pocket Meat (World) (Proto) (Aftermarket) (Unl)" + description "Pocket Meat (World) (Proto) (Aftermarket) (Unl)" + rom ( name "Pocket Meat (World) (Proto) (Aftermarket) (Unl).gba" size 861952 crc 0b029da3 sha1 9958d9a66742cc00e234a96c311b2acec40f69d1 ) ) game ( @@ -13494,6 +13902,24 @@ game ( rom ( name "Pocket Monsters - Sapphire (Japan) (Rev 1).gba" size 8388608 crc 01bd60e3 sha1 01f509671445965236ac4c6b5a354fe2f1e69f13 flags verified ) ) +game ( + name "Pocket Monsters Diamond - Pocket Monsters Pearl - Manaphy Present Campaign Senyou Cartridge (Japan) (En)" + description "Pocket Monsters Diamond - Pocket Monsters Pearl - Manaphy Present Campaign Senyou Cartridge (Japan) (En)" + rom ( name "Pocket Monsters Diamond - Pocket Monsters Pearl - Manaphy Present Campaign Senyou Cartridge (Japan) (En).gba" size 2097152 crc e31566cf sha1 3fbbd166bacdc668844e38b0ca35d6e29d11da7a ) +) + +game ( + name "Pocket Monsters Diamond - Tomodachi to Issho ni! - Present Campaign Senyou Cartridge (Japan) [b]" + description "Pocket Monsters Diamond - Tomodachi to Issho ni! - Present Campaign Senyou Cartridge (Japan) [b]" + rom ( name "Pocket Monsters Diamond - Tomodachi to Issho ni! - Present Campaign Senyou Cartridge (Japan) [b].gba" size 2097152 crc 393a77e8 sha1 147d115e4d5d758ec386dce7b0063321a1dfd583 flags baddump ) +) + +game ( + name "Pocket Monsters Pearl - Tomodachi to Issho ni! - Present Campaign Senyou Cartridge (Japan) [b]" + description "Pocket Monsters Pearl - Tomodachi to Issho ni! - Present Campaign Senyou Cartridge (Japan) [b]" + rom ( name "Pocket Monsters Pearl - Tomodachi to Issho ni! - Present Campaign Senyou Cartridge (Japan) [b].gba" size 2097152 crc 21e120be sha1 ebc831ef1e00e204975104cfbd0fd526e0f6e435 flags baddump ) +) + game ( name "Pocket Music (Europe) (En,Fr,De,Es,It)" description "Pocket Music (Europe) (En,Fr,De,Es,It)" @@ -13611,7 +14037,7 @@ game ( game ( name "Pokemon - Edicion Rubi (Spain)" description "Pokemon - Edicion Rubi (Spain)" - rom ( name "Pokemon - Edicion Rubi (Spain).gba" size 16777216 crc eb0729cf sha1 1f49f7289253dcbfecbc4c5ba3e67aa0652ec83c ) + rom ( name "Pokemon - Edicion Rubi (Spain).gba" size 16777216 crc eb0729cf sha1 1f49f7289253dcbfecbc4c5ba3e67aa0652ec83c flags verified ) ) game ( @@ -13651,9 +14077,9 @@ game ( ) game ( - name "Pokemon - FireRed Version (USA)" - description "Pokemon - FireRed Version (USA)" - rom ( name "Pokemon - FireRed Version (USA).gba" size 16777216 crc dd88761c sha1 41cb23d8dccc8ebd7c649cd8fbb58eeace6e2fdc flags verified ) + name "Pokemon - FireRed Version (USA, Europe)" + description "Pokemon - FireRed Version (USA, Europe)" + rom ( name "Pokemon - FireRed Version (USA, Europe).gba" size 16777216 crc dd88761c sha1 41cb23d8dccc8ebd7c649cd8fbb58eeace6e2fdc flags verified ) ) game ( @@ -13669,9 +14095,9 @@ game ( ) game ( - name "Pokemon - LeafGreen Version (USA)" - description "Pokemon - LeafGreen Version (USA)" - rom ( name "Pokemon - LeafGreen Version (USA).gba" size 16777216 crc d69c96cc sha1 574fa542ffebb14be69902d1d36f1ec0a4afd71e flags verified ) + name "Pokemon - LeafGreen Version (USA, Europe)" + description "Pokemon - LeafGreen Version (USA, Europe)" + rom ( name "Pokemon - LeafGreen Version (USA, Europe).gba" size 16777216 crc d69c96cc sha1 574fa542ffebb14be69902d1d36f1ec0a4afd71e flags verified ) ) game ( @@ -13717,9 +14143,9 @@ game ( ) game ( - name "Pokemon - Ruby Version (USA)" - description "Pokemon - Ruby Version (USA)" - rom ( name "Pokemon - Ruby Version (USA).gba" size 16777216 crc f0815ee7 sha1 f28b6ffc97847e94a6c21a63cacf633ee5c8df1e flags verified ) + name "Pokemon - Ruby Version (USA, Europe)" + description "Pokemon - Ruby Version (USA, Europe)" + rom ( name "Pokemon - Ruby Version (USA, Europe).gba" size 16777216 crc f0815ee7 sha1 f28b6ffc97847e94a6c21a63cacf633ee5c8df1e flags verified ) ) game ( @@ -13747,9 +14173,9 @@ game ( ) game ( - name "Pokemon - Sapphire Version (USA)" - description "Pokemon - Sapphire Version (USA)" - rom ( name "Pokemon - Sapphire Version (USA).gba" size 16777216 crc 554dedc4 sha1 3ccbbd45f8553c36463f13b938e833f652b793e4 flags verified ) + name "Pokemon - Sapphire Version (USA, Europe)" + description "Pokemon - Sapphire Version (USA, Europe)" + rom ( name "Pokemon - Sapphire Version (USA, Europe).gba" size 16777216 crc 554dedc4 sha1 3ccbbd45f8553c36463f13b938e833f652b793e4 flags verified ) ) game ( @@ -13758,12 +14184,6 @@ game ( rom ( name "Pokemon - Sapphire Version - Gotta Catch 'em All! (USA) (Unl).gba" size 33554432 crc 86a602ab sha1 14051d159d7a1266b5bfecbfd52722fd3e0711bf ) ) -game ( - name "Pokemon - Slot 2 Distribution (Japan) (En) (B5DJ)" - description "Pokemon - Slot 2 Distribution (Japan) (En) (B5DJ)" - rom ( name "Pokemon - Slot 2 Distribution (Japan) (En) (B5DJ).gba" size 2097152 crc e31566cf sha1 3fbbd166bacdc668844e38b0ca35d6e29d11da7a ) -) - game ( name "Pokemon - Slot 2 Distribution (Japan) (Proto)" description "Pokemon - Slot 2 Distribution (Japan) (Proto)" @@ -13803,7 +14223,7 @@ game ( game ( name "Pokemon - Version Saphir (France)" description "Pokemon - Version Saphir (France)" - rom ( name "Pokemon - Version Saphir (France).gba" size 16777216 crc 3581a05f sha1 c269b5692b2d0e5800ba1ddf117fda95ac648634 ) + rom ( name "Pokemon - Version Saphir (France).gba" size 16777216 crc 3581a05f sha1 c269b5692b2d0e5800ba1ddf117fda95ac648634 flags verified ) ) game ( @@ -13986,12 +14406,6 @@ game ( rom ( name "Power Poke Dash (Japan).gba" size 8388608 crc 59e7ab4c sha1 598db3dd414ec3acb8bea47192761816e401df15 ) ) -game ( - name "Power Pro Kun Pocket 1, 2 (Japan) (Promo)" - description "Power Pro Kun Pocket 1, 2 (Japan) (Promo)" - rom ( name "Power Pro Kun Pocket 1, 2 (Japan) (Promo).gba" size 8388608 crc 46493fa1 sha1 43badcefe8cad127f8f8655ee89262517399a20b ) -) - game ( name "Power Pro Kun Pocket 1, 2 (Japan)" description "Power Pro Kun Pocket 1, 2 (Japan)" @@ -14023,9 +14437,9 @@ game ( ) game ( - name "Power Pro Kun Pocket 5 (Japan) (Promo)" - description "Power Pro Kun Pocket 5 (Japan) (Promo)" - rom ( name "Power Pro Kun Pocket 5 (Japan) (Promo).gba" size 8388608 crc 969ac691 sha1 f9fd4c8ee4f274c751551f056dc868abd0355390 ) + name "Power Pro Kun Pocket 5 (Japan) (Demo) (Kiosk)" + description "Power Pro Kun Pocket 5 (Japan) (Demo) (Kiosk)" + rom ( name "Power Pro Kun Pocket 5 (Japan) (Demo) (Kiosk).gba" size 8388608 crc 969ac691 sha1 f9fd4c8ee4f274c751551f056dc868abd0355390 ) ) game ( @@ -14040,12 +14454,6 @@ game ( rom ( name "Power Pro Kun Pocket 5 (Japan).gba" size 8388608 crc 06f0f8d4 sha1 15bc24f0f47e0317c849c1c33a36357a43def74c ) ) -game ( - name "Power Pro Kun Pocket 6 (Japan) (Promo)" - description "Power Pro Kun Pocket 6 (Japan) (Promo)" - rom ( name "Power Pro Kun Pocket 6 (Japan) (Promo).gba" size 8388608 crc 023a9a75 sha1 066d2086d776c66aa566eac211a0e9b45f1942f6 ) -) - game ( name "Power Pro Kun Pocket 6 (Japan)" description "Power Pro Kun Pocket 6 (Japan)" @@ -14155,9 +14563,9 @@ game ( ) game ( - name "Prehistorik Man (USA) (En,Fr,De,Es,It,Nl) (Beta)" - description "Prehistorik Man (USA) (En,Fr,De,Es,It,Nl) (Beta)" - rom ( name "Prehistorik Man (USA) (En,Fr,De,Es,It,Nl) (Beta).gba" size 4194304 crc abb50d93 sha1 dc789663025c8e5122622ce4fc6d0953a5656bd6 ) + name "Prehistorik Man (USA, Europe) (En,Fr,De,Es,It,Nl) (Beta)" + description "Prehistorik Man (USA, Europe) (En,Fr,De,Es,It,Nl) (Beta)" + rom ( name "Prehistorik Man (USA, Europe) (En,Fr,De,Es,It,Nl) (Beta).gba" size 4194304 crc abb50d93 sha1 dc789663025c8e5122622ce4fc6d0953a5656bd6 ) ) game ( @@ -14383,9 +14791,9 @@ game ( ) game ( - name "Racing Fever (Europe) (En,De,Es,It)" - description "Racing Fever (Europe) (En,De,Es,It)" - rom ( name "Racing Fever (Europe) (En,De,Es,It).gba" size 4194304 crc e40ec737 sha1 9bb5c036bca8f0d2e06013cac7ea6148a4f7f512 ) + name "R3D Demo (Europe) (Demo)" + description "R3D Demo (Europe) (Demo)" + rom ( name "R3D Demo (Europe) (Demo).gba" size 8388608 crc 3e7f9100 sha1 48261a7984808f573a1b07be647c02b941af6247 ) ) game ( @@ -14394,6 +14802,18 @@ game ( rom ( name "Racing Fever (France).gba" size 4194304 crc 4f61dedb sha1 67eb3051c7527692cfd7515ea367796fab3a1362 ) ) +game ( + name "Racing Fever (Europe) (En,De,Es,It)" + description "Racing Fever (Europe) (En,De,Es,It)" + rom ( name "Racing Fever (Europe) (En,De,Es,It).gba" size 4194304 crc e40ec737 sha1 9bb5c036bca8f0d2e06013cac7ea6148a4f7f512 ) +) + +game ( + name "Racing Gears Advance (USA) (Beta)" + description "Racing Gears Advance (USA) (Beta)" + rom ( name "Racing Gears Advance (USA) (Beta).gba" size 8388608 crc 7a3820b3 sha1 ff18dfe7d75a8154c0dcc3970e5d0d4cb75c3568 ) +) + game ( name "Racing Gears Advance (Europe) (En,Fr,De,Es,It)" description "Racing Gears Advance (Europe) (En,Fr,De,Es,It)" @@ -14409,7 +14829,7 @@ game ( game ( name "Rampage - Puzzle Attack (USA, Europe)" description "Rampage - Puzzle Attack (USA, Europe)" - rom ( name "Rampage - Puzzle Attack (USA, Europe).gba" size 4194304 crc 8eca2b0f sha1 35c4ace4044f2171dc90a1195ec83ae57324fc83 ) + rom ( name "Rampage - Puzzle Attack (USA, Europe).gba" size 4194304 crc 8eca2b0f sha1 35c4ace4044f2171dc90a1195ec83ae57324fc83 flags verified ) ) game ( @@ -14418,12 +14838,6 @@ game ( rom ( name "Rapala Pro Fishing (USA, Europe).gba" size 4194304 crc 964d39a7 sha1 e3df6fe7a447ab30faf6fd7d4c57e88f987a5639 ) ) -game ( - name "Ratatouille (Greece) (En)" - description "Ratatouille (Greece) (En)" - rom ( name "Ratatouille (Greece) (En).gba" size 8388608 crc 3e1711c7 sha1 58f2fa1d7e531c7345b11db268e1bbc10372bebc ) -) - game ( name "Ratatouille (USA)" description "Ratatouille (USA)" @@ -14448,6 +14862,12 @@ game ( rom ( name "Ratatouille (Europe) (En,It,Sv,No,Da).gba" size 8388608 crc 82f9c596 sha1 a5c4a636979c06670a81428c778ff76ed2c65eee ) ) +game ( + name "Ratatouille (Australia, Greece) (En)" + description "Ratatouille (Australia, Greece) (En)" + rom ( name "Ratatouille (Australia, Greece) (En).gba" size 8388608 crc 3e1711c7 sha1 58f2fa1d7e531c7345b11db268e1bbc10372bebc flags verified ) +) + game ( name "Rave Master - Special Attack Force! (USA)" description "Rave Master - Special Attack Force! (USA)" @@ -14496,18 +14916,6 @@ game ( rom ( name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi) (Beta).gba" size 8388608 crc 8f34b14f sha1 064f6b09732f4225f5964d0e8bd386affb83e3d7 ) ) -game ( - name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" - description "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" - rom ( name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba" size 8388608 crc 29f83314 sha1 21b7296d29486ccab68bdfa45ab24b9d370d052c ) -) - -game ( - name "Rayman 3 (USA) (En,Fr,Es)" - description "Rayman 3 (USA) (En,Fr,Es)" - rom ( name "Rayman 3 (USA) (En,Fr,Es).gba" size 8388608 crc d1613266 sha1 1a8fb488aac9af4d3d42046750bdf429f48ac391 ) -) - game ( name "Rayman 3 (USA) (Beta)" description "Rayman 3 (USA) (Beta)" @@ -14515,9 +14923,15 @@ game ( ) game ( - name "Rayman Advance (Europe) (En,Fr,De,Es,It) (Beta)" - description "Rayman Advance (Europe) (En,Fr,De,Es,It) (Beta)" - rom ( name "Rayman Advance (Europe) (En,Fr,De,Es,It) (Beta).gba" size 8388608 crc 4b1b4e02 sha1 2a473e6a0664412ead33aa9889912dc25db93714 ) + name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" + description "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi)" + rom ( name "Rayman 3 (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da,Fi).gba" size 8388608 crc 29f83314 sha1 21b7296d29486ccab68bdfa45ab24b9d370d052c flags verified ) +) + +game ( + name "Rayman 3 (USA) (En,Fr,Es)" + description "Rayman 3 (USA) (En,Fr,Es)" + rom ( name "Rayman 3 (USA) (En,Fr,Es).gba" size 8388608 crc d1613266 sha1 1a8fb488aac9af4d3d42046750bdf429f48ac391 ) ) game ( @@ -14529,7 +14943,13 @@ game ( game ( name "Rayman Advance (Europe) (En,Fr,De,Es,It)" description "Rayman Advance (Europe) (En,Fr,De,Es,It)" - rom ( name "Rayman Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc b43783b4 sha1 6a32d270848ae302a3e4fb873e53b663c2db4811 ) + rom ( name "Rayman Advance (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc b43783b4 sha1 6a32d270848ae302a3e4fb873e53b663c2db4811 flags verified ) +) + +game ( + name "Rayman Advance (Europe) (En,Fr,De,Es,It) (Beta)" + description "Rayman Advance (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Rayman Advance (Europe) (En,Fr,De,Es,It) (Beta).gba" size 8388608 crc 4b1b4e02 sha1 2a473e6a0664412ead33aa9889912dc25db93714 ) ) game ( @@ -14583,7 +15003,13 @@ game ( game ( name "Ready 2 Rumble Boxing - Round 2 (Europe) (En,Fr,De)" description "Ready 2 Rumble Boxing - Round 2 (Europe) (En,Fr,De)" - rom ( name "Ready 2 Rumble Boxing - Round 2 (Europe) (En,Fr,De).gba" size 4194304 crc e418e962 sha1 57d06e405b281f68800b986bd9ff1257e4466939 ) + rom ( name "Ready 2 Rumble Boxing - Round 2 (Europe) (En,Fr,De).gba" size 4194304 crc e418e962 sha1 57d06e405b281f68800b986bd9ff1257e4466939 flags verified ) +) + +game ( + name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It) (Beta)" + description "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It) (Beta).gba" size 4194304 crc 2189021c sha1 b6e2167272a68bd4e3833cccd68929d50a27a426 ) ) game ( @@ -14598,12 +15024,6 @@ game ( rom ( name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc e448c5d4 sha1 669c47e62f2388ce0ba676f3dc641b5ad2ddb5c5 flags verified ) ) -game ( - name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It) (Beta)" - description "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It) (Beta)" - rom ( name "Rebelstar - Tactical Command (Europe) (En,Fr,De,Es,It) (Beta).gba" size 4194304 crc 2189021c sha1 b6e2167272a68bd4e3833cccd68929d50a27a426 ) -) - game ( name "Recca no Honoo - The Game (Japan)" description "Recca no Honoo - The Game (Japan)" @@ -14629,21 +15049,15 @@ game ( ) game ( - name "Remute - Unity (World) (Aftermarket) (Unl)" - description "Remute - Unity (World) (Aftermarket) (Unl)" - rom ( name "Remute - Unity (World) (Aftermarket) (Unl).gba" size 33554432 crc 6cd42a32 sha1 d8001b07885557ee32608c661e202a257d3e8c3d ) -) - -game ( - name "Ren Zhe Shen Gui 2 (Taiwan) (Unl)" - description "Ren Zhe Shen Gui 2 (Taiwan) (Unl)" - rom ( name "Ren Zhe Shen Gui 2 (Taiwan) (Unl).gba" size 33554432 crc f4641711 sha1 efe55f22035576ebe0be6012c1b9d32238bb0ca2 ) + name "Renzhe Shen Gui 2 (Taiwan) (Unl)" + description "Renzhe Shen Gui 2 (Taiwan) (Unl)" + rom ( name "Renzhe Shen Gui 2 (Taiwan) (Unl).gba" size 33554432 crc f4641711 sha1 efe55f22035576ebe0be6012c1b9d32238bb0ca2 ) ) game ( name "Rescue Heroes - Billy Blazes! (USA)" description "Rescue Heroes - Billy Blazes! (USA)" - rom ( name "Rescue Heroes - Billy Blazes! (USA).gba" size 4194304 crc 8111261c sha1 481fd8ab9e8e980039e244ba31a6dff057235210 ) + rom ( name "Rescue Heroes - Billy Blazes! (USA).gba" size 4194304 crc 8111261c sha1 481fd8ab9e8e980039e244ba31a6dff057235210 flags verified ) ) game ( @@ -14805,7 +15219,7 @@ game ( game ( name "Robots (Europe) (En,Fr,De,Es,It)" description "Robots (Europe) (En,Fr,De,Es,It)" - rom ( name "Robots (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 2acbdb64 sha1 26be826817f35433b3609d13ee75a3872e94d616 ) + rom ( name "Robots (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 2acbdb64 sha1 26be826817f35433b3609d13ee75a3872e94d616 flags verified ) ) game ( @@ -14886,12 +15300,30 @@ game ( rom ( name "Rockman & Forte (Japan).gba" size 8388608 crc ce2b48c4 sha1 f8eb056745e8b58c1ef4bfef995c77a27aadc57a flags verified ) ) +game ( + name "Rockman EXE - Battle Chip GP (Japan)" + description "Rockman EXE - Battle Chip GP (Japan)" + rom ( name "Rockman EXE - Battle Chip GP (Japan).gba" size 8388608 crc 9217fb18 sha1 f39992851257a1567f3bfca81dd269f37469bb67 ) +) + +game ( + name "Rockman EXE - Battle Chip GP (Japan) (Virtual Console)" + description "Rockman EXE - Battle Chip GP (Japan) (Virtual Console)" + rom ( name "Rockman EXE - Battle Chip GP (Japan) (Virtual Console).gba" size 8388608 crc f37bf038 sha1 9816fdb5f076c601287f5dfb3c7218150a75f2f6 ) +) + game ( name "Rockman EXE 4 - Tournament Blue Moon (Japan) (Rev 1) (Virtual Console)" description "Rockman EXE 4 - Tournament Blue Moon (Japan) (Rev 1) (Virtual Console)" rom ( name "Rockman EXE 4 - Tournament Blue Moon (Japan) (Rev 1) (Virtual Console).gba" size 8388608 crc 0a27789e sha1 bfded71514df71d0449f9c972a4f6356970796a1 ) ) +game ( + name "Rockman EXE 4 - Tournament Blue Moon (Japan) (Rev 1)" + description "Rockman EXE 4 - Tournament Blue Moon (Japan) (Rev 1)" + rom ( name "Rockman EXE 4 - Tournament Blue Moon (Japan) (Rev 1).gba" size 8388608 crc 709bbf07 sha1 c46305f0398f75230b7f6f62d39167dfcc7b1778 ) +) + game ( name "Rockman EXE 4 - Tournament Blue Moon (Japan)" description "Rockman EXE 4 - Tournament Blue Moon (Japan)" @@ -14976,18 +15408,6 @@ game ( rom ( name "Rockman EXE 6 - Dennoujuu Gregar (Japan) (Virtual Console).gba" size 8388608 crc d0fdbefb sha1 678787c7d7cbee119eb524211487fb5dcd01426b ) ) -game ( - name "Rockman EXE Battle Chip GP (Japan) (Virtual Console)" - description "Rockman EXE Battle Chip GP (Japan) (Virtual Console)" - rom ( name "Rockman EXE Battle Chip GP (Japan) (Virtual Console).gba" size 8388608 crc f37bf038 sha1 9816fdb5f076c601287f5dfb3c7218150a75f2f6 ) -) - -game ( - name "Rockman EXE Battle Chip GP (Japan)" - description "Rockman EXE Battle Chip GP (Japan)" - rom ( name "Rockman EXE Battle Chip GP (Japan).gba" size 8388608 crc 9217fb18 sha1 f39992851257a1567f3bfca81dd269f37469bb67 ) -) - game ( name "Rockman Zero (Japan) (Virtual Console)" description "Rockman Zero (Japan) (Virtual Console)" @@ -15078,6 +15498,30 @@ game ( rom ( name "Rugrats - Travesuras en el Castillo (Spain).gba" size 4194304 crc 0bcab7d0 sha1 89448f91091a46deaebaddbaaada43522f387465 ) ) +game ( + name "S World 3 (World) (Beta 4) (Unl)" + description "S World 3 (World) (Beta 4) (Unl)" + rom ( name "S World 3 (World) (Beta 4) (Unl).gba" size 265800 crc 9d5e128c sha1 243555734e942b3ddba2d7834805e56eb72403c4 ) +) + +game ( + name "S World 3 (World) (Beta 3) (Unl)" + description "S World 3 (World) (Beta 3) (Unl)" + rom ( name "S World 3 (World) (Beta 3) (Unl).gba" size 43296 crc 3bc15e46 sha1 830f34779783f645dc88c4b00f8d85ca5f87f904 ) +) + +game ( + name "S World 3 (World) (Beta 2) (Unl)" + description "S World 3 (World) (Beta 2) (Unl)" + rom ( name "S World 3 (World) (Beta 2) (Unl).gba" size 12844 crc 34ad13fe sha1 5de0d42c33c616d8b27bb32050b10853cdea232d ) +) + +game ( + name "S World 3 (World) (Beta 1) (Unl)" + description "S World 3 (World) (Beta 1) (Unl)" + rom ( name "S World 3 (World) (Beta 1) (Unl).gba" size 10144 crc 6b1a6173 sha1 201d6c313fed6b263ba31872be7032cfe874c50b ) +) + game ( name "Sabre Wulf (Europe) (En,Fr,De)" description "Sabre Wulf (Europe) (En,Fr,De)" @@ -15165,7 +15609,7 @@ game ( game ( name "Samurai Jack - The Amulet of Time (USA, Europe)" description "Samurai Jack - The Amulet of Time (USA, Europe)" - rom ( name "Samurai Jack - The Amulet of Time (USA, Europe).gba" size 8388608 crc b250366c sha1 27a5604b4aa89d2fec216aeac2b99e76165f531f ) + rom ( name "Samurai Jack - The Amulet of Time (USA, Europe).gba" size 8388608 crc b250366c sha1 27a5604b4aa89d2fec216aeac2b99e76165f531f flags verified ) ) game ( @@ -15195,7 +15639,7 @@ game ( game ( name "Santa Claus Jr. Advance (Europe)" description "Santa Claus Jr. Advance (Europe)" - rom ( name "Santa Claus Jr. Advance (Europe).gba" size 4194304 crc fe3e6769 sha1 60d6b482c4be9fb61a172f3864c9b35afc275980 ) + rom ( name "Santa Claus Jr. Advance (Europe).gba" size 4194304 crc fe3e6769 sha1 60d6b482c4be9fb61a172f3864c9b35afc275980 flags verified ) ) game ( @@ -15594,12 +16038,6 @@ game ( rom ( name "Sheep (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 75a92925 sha1 cb200350b4dc01dcdb0a52af11286aaca15cd786 ) ) -game ( - name "Shi Rui Ke II - Yu Mei Ren (Taiwan) (Unl)" - description "Shi Rui Ke II - Yu Mei Ren (Taiwan) (Unl)" - rom ( name "Shi Rui Ke II - Yu Mei Ren (Taiwan) (Unl).gba" size 33554432 crc 16d294d1 sha1 8033cc6c2c7f929844c39304b7faaf90115f1abc ) -) - game ( name "Shifting Gears - Road Trip (USA)" description "Shifting Gears - Road Trip (USA)" @@ -15618,18 +16056,18 @@ game ( rom ( name "Shikakui Atama o Maruku Suru. Advance - Kokugo, Sansuu, Shakai, Rika (Japan).gba" size 4194304 crc 07695a6c sha1 c1cf1478d79daf6c2717df6f19cad806bd7f6429 ) ) -game ( - name "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan) (Rev 1)" - description "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan) (Rev 1)" - rom ( name "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan) (Rev 1).gba" size 4194304 crc 5546b016 sha1 c7c94199bac6a1f69356413031b5a49cb30c93d1 ) -) - game ( name "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan)" description "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan)" rom ( name "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan).gba" size 4194304 crc f29e6e2d sha1 b2f100650af2c8d6ec02c0a71774eeba22d6be2f ) ) +game ( + name "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan) (Rev 1)" + description "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan) (Rev 1)" + rom ( name "Shimura Ken no Baka Tonosama - Bakushou Tenka Touitsu Game (Japan) (Rev 1).gba" size 4194304 crc 5546b016 sha1 c7c94199bac6a1f69356413031b5a49cb30c93d1 ) +) + game ( name "Shin Bokura no Taiyou - Gyakushuu no Sabata (Japan)" description "Shin Bokura no Taiyou - Gyakushuu no Sabata (Japan)" @@ -15660,6 +16098,30 @@ game ( rom ( name "Shin Megami Tensei (Japan).gba" size 8388608 crc b857c3c5 sha1 7851f7f061693d664672f47f2d2d714829cf52ac ) ) +game ( + name "Shin Megami Tensei - Devil Children - Honoo no Sho (Japan)" + description "Shin Megami Tensei - Devil Children - Honoo no Sho (Japan)" + rom ( name "Shin Megami Tensei - Devil Children - Honoo no Sho (Japan).gba" size 8388608 crc 9a0903bc sha1 8c29d6921e7db8b0e71094d32e32066ac13c500d ) +) + +game ( + name "Shin Megami Tensei - Devil Children - Koori no Sho (Japan)" + description "Shin Megami Tensei - Devil Children - Koori no Sho (Japan)" + rom ( name "Shin Megami Tensei - Devil Children - Koori no Sho (Japan).gba" size 8388608 crc ad80d5f9 sha1 8470a93bded96270d1403bb485f32c42edf1462a flags verified ) +) + +game ( + name "Shin Megami Tensei - Devil Children - Messiah Riser (Japan)" + description "Shin Megami Tensei - Devil Children - Messiah Riser (Japan)" + rom ( name "Shin Megami Tensei - Devil Children - Messiah Riser (Japan).gba" size 8388608 crc 0ec98c51 sha1 9387947baa410c748ec5fab1ce9a07ae8047e398 ) +) + +game ( + name "Shin Megami Tensei - Devil Children - Puzzle de Call! (Japan)" + description "Shin Megami Tensei - Devil Children - Puzzle de Call! (Japan)" + rom ( name "Shin Megami Tensei - Devil Children - Puzzle de Call! (Japan).gba" size 4194304 crc ea8a185a sha1 e70fc457b56c8e27ab63e491706b88232f598452 ) +) + game ( name "Shin Megami Tensei Devil Children - Hikari no Sho (Japan)" description "Shin Megami Tensei Devil Children - Hikari no Sho (Japan)" @@ -15667,27 +16129,9 @@ game ( ) game ( - name "Shin Megami Tensei Devil Children - Honoo no Sho (Japan)" - description "Shin Megami Tensei Devil Children - Honoo no Sho (Japan)" - rom ( name "Shin Megami Tensei Devil Children - Honoo no Sho (Japan).gba" size 8388608 crc 9a0903bc sha1 8c29d6921e7db8b0e71094d32e32066ac13c500d ) -) - -game ( - name "Shin Megami Tensei Devil Children - Koori no Sho (Japan)" - description "Shin Megami Tensei Devil Children - Koori no Sho (Japan)" - rom ( name "Shin Megami Tensei Devil Children - Koori no Sho (Japan).gba" size 8388608 crc ad80d5f9 sha1 8470a93bded96270d1403bb485f32c42edf1462a flags verified ) -) - -game ( - name "Shin Megami Tensei Devil Children - Messiah Riser (Japan)" - description "Shin Megami Tensei Devil Children - Messiah Riser (Japan)" - rom ( name "Shin Megami Tensei Devil Children - Messiah Riser (Japan).gba" size 8388608 crc 0ec98c51 sha1 9387947baa410c748ec5fab1ce9a07ae8047e398 ) -) - -game ( - name "Shin Megami Tensei Devil Children - Puzzle de Call! (Japan)" - description "Shin Megami Tensei Devil Children - Puzzle de Call! (Japan)" - rom ( name "Shin Megami Tensei Devil Children - Puzzle de Call! (Japan).gba" size 4194304 crc ea8a185a sha1 e70fc457b56c8e27ab63e491706b88232f598452 ) + name "Shin Megami Tensei Devil Children - Yami no Sho (Japan)" + description "Shin Megami Tensei Devil Children - Yami no Sho (Japan)" + rom ( name "Shin Megami Tensei Devil Children - Yami no Sho (Japan).gba" size 8388608 crc e0e153b7 sha1 236fd0e7c14f5d6db7fa2083766324341b9e5b39 ) ) game ( @@ -15696,12 +16140,6 @@ game ( rom ( name "Shin Megami Tensei Devil Children - Yami no Sho (Japan) (Beta).gba" size 8388608 crc 81f30ebc sha1 c2db9b977758b4f350340f981baffcc0bba0c6c2 ) ) -game ( - name "Shin Megami Tensei Devil Children - Yami no Sho (Japan)" - description "Shin Megami Tensei Devil Children - Yami no Sho (Japan)" - rom ( name "Shin Megami Tensei Devil Children - Yami no Sho (Japan).gba" size 8388608 crc e0e153b7 sha1 236fd0e7c14f5d6db7fa2083766324341b9e5b39 ) -) - game ( name "Shin Megami Tensei II (Japan)" description "Shin Megami Tensei II (Japan)" @@ -15714,18 +16152,18 @@ game ( rom ( name "Shin Nihon Pro Wrestling - Toukon Retsuden Advance (Japan).gba" size 8388608 crc 9f0b8b79 sha1 8c7d119f4e9ac6dab2c308d1dfad5eabb0837014 ) ) -game ( - name "Shin Sangoku Musou Advance (Japan)" - description "Shin Sangoku Musou Advance (Japan)" - rom ( name "Shin Sangoku Musou Advance (Japan).gba" size 16777216 crc fe1be6c1 sha1 677cd51c1ecdde73a6f40ec2cd30d35c77db459a ) -) - game ( name "Shin Sangoku Musou Advance (Japan) (Rev 1)" description "Shin Sangoku Musou Advance (Japan) (Rev 1)" rom ( name "Shin Sangoku Musou Advance (Japan) (Rev 1).gba" size 16777216 crc 7ceded10 sha1 be2bfa709478dc482e80fb476c1ee846b703bcbb ) ) +game ( + name "Shin Sangoku Musou Advance (Japan)" + description "Shin Sangoku Musou Advance (Japan)" + rom ( name "Shin Sangoku Musou Advance (Japan).gba" size 16777216 crc fe1be6c1 sha1 677cd51c1ecdde73a6f40ec2cd30d35c77db459a ) +) + game ( name "Shingata Medarot - Kabuto Version (Japan)" description "Shingata Medarot - Kabuto Version (Japan)" @@ -15828,6 +16266,12 @@ game ( rom ( name "Shiren Monsters - Netsal (Japan) (Demo) (Kiosk, GameCube).gba" size 16777216 crc 25b0b122 sha1 2ebd243709a9b0af16c6c0b0404fb02999eefffd flags verified ) ) +game ( + name "Shiruike II - Yu Meiren (Taiwan) (Unl)" + description "Shiruike II - Yu Meiren (Taiwan) (Unl)" + rom ( name "Shiruike II - Yu Meiren (Taiwan) (Unl).gba" size 33554432 crc 16d294d1 sha1 8033cc6c2c7f929844c39304b7faaf90115f1abc ) +) + game ( name "Shrek - Hassle at the Castle (USA) (En,Fr,De,Es,It,Nl)" description "Shrek - Hassle at the Castle (USA) (En,Fr,De,Es,It,Nl)" @@ -15843,7 +16287,7 @@ game ( game ( name "Shrek - Reekin' Havoc (USA) (En,Fr,De,Es,It,Nl)" description "Shrek - Reekin' Havoc (USA) (En,Fr,De,Es,It,Nl)" - rom ( name "Shrek - Reekin' Havoc (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 63f49ba9 sha1 af0bc8338e49be78ce6e85b59d1ddfca8a10f290 ) + rom ( name "Shrek - Reekin' Havoc (USA) (En,Fr,De,Es,It,Nl).gba" size 8388608 crc 63f49ba9 sha1 af0bc8338e49be78ce6e85b59d1ddfca8a10f290 flags verified ) ) game ( @@ -16074,6 +16518,12 @@ game ( rom ( name "Sims, The - Bustin' Out (USA) (En,Fr,De,Es,It,Nl) (Rev 1).gba" size 16777216 crc d1183501 sha1 7038fa0e4cb8aeac9e48a0b45574db66cba39e73 flags verified ) ) +game ( + name "Sips (World) (Aftermarket) (Unl)" + description "Sips (World) (Aftermarket) (Unl)" + rom ( name "Sips (World) (Aftermarket) (Unl).gba" size 6235380 crc 5c1fb22d sha1 bb725df7226307d55df04365f85e5698b199c3c9 ) +) + game ( name "Sister Princess - RePure (Japan)" description "Sister Princess - RePure (Japan)" @@ -16122,6 +16572,30 @@ game ( rom ( name "Sky Dancers - They Magically Fly! (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 3af1063b sha1 df749ac7e33a1c7ede3faadb6648a8e53fa77048 ) ) +game ( + name "Skyland (World) (v2023.5.5.0) (Proto) (Aftermarket) (Unl)" + description "Skyland (World) (v2023.5.5.0) (Proto) (Aftermarket) (Unl)" + rom ( name "Skyland (World) (v2023.5.5.0) (Proto) (Aftermarket) (Unl).gba" size 15887876 crc c798529d sha1 ea4a6494bcec25757f657c69550c91190e46cebd ) +) + +game ( + name "Skyland (World) (v2023.5.15.0) (Proto) (Aftermarket) (Unl)" + description "Skyland (World) (v2023.5.15.0) (Proto) (Aftermarket) (Unl)" + rom ( name "Skyland (World) (v2023.5.15.0) (Proto) (Aftermarket) (Unl).gba" size 15894868 crc af572de8 sha1 997bf192369d48433a7c35187c7e1d0b5fcc16e0 ) +) + +game ( + name "Skyland (World) (v2023.5.26.0) (Proto) (Aftermarket) (Unl)" + description "Skyland (World) (v2023.5.26.0) (Proto) (Aftermarket) (Unl)" + rom ( name "Skyland (World) (v2023.5.26.0) (Proto) (Aftermarket) (Unl).gba" size 15900084 crc df05edff sha1 1328d17668480b4e9bea338662532ace332c74a9 ) +) + +game ( + name "Skyland (World) (v2023.8.1.1) (Proto) (Aftermarket) (Unl)" + description "Skyland (World) (v2023.8.1.1) (Proto) (Aftermarket) (Unl)" + rom ( name "Skyland (World) (v2023.8.1.1) (Proto) (Aftermarket) (Unl).gba" size 16075456 crc d271c516 sha1 0dbdf16b23afb70229eff2de269fd5d73659d745 ) +) + game ( name "Slime Morimori Dragon Quest - Shougeki no Shippo Dan (Japan)" description "Slime Morimori Dragon Quest - Shougeki no Shippo Dan (Japan)" @@ -16161,7 +16635,7 @@ game ( game ( name "Smuggler's Run (Europe) (En,Fr,De,Es,It)" description "Smuggler's Run (Europe) (En,Fr,De,Es,It)" - rom ( name "Smuggler's Run (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 3ae0afc8 sha1 e87067719da93f0d7c8136cdf5717612a6c15034 ) + rom ( name "Smuggler's Run (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 3ae0afc8 sha1 e87067719da93f0d7c8136cdf5717612a6c15034 flags verified ) ) game ( @@ -16206,6 +16680,12 @@ game ( rom ( name "Soccer Kid (USA, Europe).gba" size 4194304 crc d3485f5a sha1 4e7dc4d47ef064131990fe3ebb340edeaed321ef flags verified ) ) +game ( + name "Soccer Mania (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + description "Soccer Mania (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da)" + rom ( name "Soccer Mania (USA, Europe) (En,Fr,De,Es,It,Nl,Sv,Da).gba" size 8388608 crc 73ef3a35 sha1 05799b99395aba04dfe5ae8af019e4d70cb8e61b ) +) + game ( name "Sonic 3 - Fighter Sonic (USA) (Unl)" description "Sonic 3 - Fighter Sonic (USA) (Unl)" @@ -16248,6 +16728,18 @@ game ( rom ( name "Sonic Advance (Japan) (En,Ja) (Rev 1).gba" size 8388608 crc 85957a24 sha1 f43faca5d8df354a63471aebfea3be125e797e51 ) ) +game ( + name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" + description "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" + rom ( name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 6c6c65a3 sha1 2aa6ee2cf2b0ebfafbea6d6d24165b252a7e329e ) +) + +game ( + name "Sonic Advance 2 (USA) (Beta) (2002-10-25)" + description "Sonic Advance 2 (USA) (Beta) (2002-10-25)" + rom ( name "Sonic Advance 2 (USA) (Beta) (2002-10-25).gba" size 16777216 crc 95ab3867 sha1 3368642fc4157824af63367e2a685b7d6ee9b09d ) +) + game ( name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It)" description "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It)" @@ -16266,30 +16758,6 @@ game ( rom ( name "Sonic Advance 2 (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 89509891 sha1 b0f64bdca097f2de8f05ac4c8caea2b80c5faeb1 flags verified ) ) -game ( - name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" - description "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" - rom ( name "Sonic Advance 2 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 6c6c65a3 sha1 2aa6ee2cf2b0ebfafbea6d6d24165b252a7e329e ) -) - -game ( - name "Sonic Advance 2 (USA) (Beta)" - description "Sonic Advance 2 (USA) (Beta)" - rom ( name "Sonic Advance 2 (USA) (Beta).gba" size 16777216 crc 95ab3867 sha1 3368642fc4157824af63367e2a685b7d6ee9b09d ) -) - -game ( - name "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" - description "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" - rom ( name "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 1f36892f sha1 9fc8e926fc5472a1e34e3251c5d316526dc7a7a9 ) -) - -game ( - name "Sonic Advance 3 (Japan) (Demo) (Kiosk, GameCube)" - description "Sonic Advance 3 (Japan) (Demo) (Kiosk, GameCube)" - rom ( name "Sonic Advance 3 (Japan) (Demo) (Kiosk, GameCube).gba" size 16777216 crc 0594d496 sha1 9c3f18112c126ca08403408a844a3a83967eb4dc flags verified ) -) - game ( name "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It) (Beta)" description "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It) (Beta)" @@ -16314,6 +16782,18 @@ game ( rom ( name "Sonic Advance 3 (Europe) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 5bf83456 sha1 685af3a2dc0f1b3f8922e73ec42c1dc92e210e39 flags verified ) ) +game ( + name "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" + description "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console)" + rom ( name "Sonic Advance 3 (Japan) (En,Ja,Fr,De,Es,It) (Virtual Console).gba" size 16777216 crc 1f36892f sha1 9fc8e926fc5472a1e34e3251c5d316526dc7a7a9 ) +) + +game ( + name "Sonic Advance 3 (Japan) (Demo) (Kiosk, GameCube)" + description "Sonic Advance 3 (Japan) (Demo) (Kiosk, GameCube)" + rom ( name "Sonic Advance 3 (Japan) (Demo) (Kiosk, GameCube).gba" size 16777216 crc 0594d496 sha1 9c3f18112c126ca08403408a844a3a83967eb4dc flags verified ) +) + game ( name "Sonic Battle (Japan) (En,Ja)" description "Sonic Battle (Japan) (En,Ja)" @@ -16323,7 +16803,7 @@ game ( game ( name "Sonic Battle (USA) (En,Ja,Fr,De,Es,It)" description "Sonic Battle (USA) (En,Ja,Fr,De,Es,It)" - rom ( name "Sonic Battle (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 9ec9d86f sha1 8cf4fbbe73f6b1907ab9997caab4c4e7d9708937 ) + rom ( name "Sonic Battle (USA) (En,Ja,Fr,De,Es,It).gba" size 16777216 crc 9ec9d86f sha1 8cf4fbbe73f6b1907ab9997caab4c4e7d9708937 flags verified ) ) game ( @@ -16512,18 +16992,18 @@ game ( rom ( name "Spider-Man 3 (USA) (Unl).gba" size 33554432 crc 3e1b693a sha1 54d22c0fe81e78380fc2d839aa800f36fc1ef311 ) ) -game ( - name "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany) (Beta)" - description "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany) (Beta)" - rom ( name "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany) (Beta).gba" size 4183576 crc caaaefb6 sha1 53c4bb950d9b92918f26aeb7b0105604d0263ba1 ) -) - game ( name "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany)" description "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany)" rom ( name "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany).gba" size 4194304 crc 4785eee0 sha1 ce8f271e143456616a9649fee7d47ef1602ee497 ) ) +game ( + name "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany) (Beta)" + description "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany) (Beta)" + rom ( name "Spirit - Der Wilde Mustang - Auf der Suche nach Homeland (Germany) (Beta).gba" size 4183576 crc caaaefb6 sha1 53c4bb950d9b92918f26aeb7b0105604d0263ba1 ) +) + game ( name "Spirit - L'Etalon des Plaines - A la Recherche de la Terre Natale (France)" description "Spirit - L'Etalon des Plaines - A la Recherche de la Terre Natale (France)" @@ -16615,15 +17095,15 @@ game ( ) game ( - name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08) (05-16)" - description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08) (05-16)" - rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08) (05-16).gba" size 315572 crc 49754ee4 sha1 d14787d2af88af2907f71744d4b4a933b38ee31a ) + name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08T051624)" + description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08T051624)" + rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08T051624).gba" size 315572 crc 49754ee4 sha1 d14787d2af88af2907f71744d4b4a933b38ee31a ) ) game ( - name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08) (07-47)" - description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08) (07-47)" - rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08) (07-47).gba" size 342160 crc b83d7e0d sha1 bc0833743e90b6cff8f51906e12f15748fed4ed6 ) + name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08T074756)" + description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08T074756)" + rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-01-08T074756).gba" size 342160 crc b83d7e0d sha1 bc0833743e90b6cff8f51906e12f15748fed4ed6 ) ) game ( @@ -16669,15 +17149,15 @@ game ( ) game ( - name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06) (11-34)" - description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06) (11-34)" - rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06) (11-34).gba" size 2470464 crc 40cc2e8a sha1 071e9a6c09ccd6e52d1d6cc40a0ebea3e8dd80c3 ) + name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06T113400)" + description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06T113400)" + rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06T113400).gba" size 2470464 crc 40cc2e8a sha1 071e9a6c09ccd6e52d1d6cc40a0ebea3e8dd80c3 ) ) game ( - name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06) (11-39)" - description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06) (11-39)" - rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06) (11-39).gba" size 3011936 crc ff4f1ee7 sha1 909a6cc0930818de20489cfcdd967280b403272b ) + name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06T113900)" + description "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06T113900)" + rom ( name "SpongeBob SquarePants - SuperSponge (USA, Europe) (Beta) (2001-06-06T113900).gba" size 3011936 crc ff4f1ee7 sha1 909a6cc0930818de20489cfcdd967280b403272b ) ) game ( @@ -16947,7 +17427,7 @@ game ( game ( name "Star Wars - The New Droid Army (Europe) (En,Fr,De,Es)" description "Star Wars - The New Droid Army (Europe) (En,Fr,De,Es)" - rom ( name "Star Wars - The New Droid Army (Europe) (En,Fr,De,Es).gba" size 8388608 crc 677854af sha1 4966ce40938df2b0ffd262c6aa6c4461b9fa8922 ) + rom ( name "Star Wars - The New Droid Army (Europe) (En,Fr,De,Es).gba" size 8388608 crc 677854af sha1 4966ce40938df2b0ffd262c6aa6c4461b9fa8922 flags verified ) ) game ( @@ -16993,9 +17473,9 @@ game ( ) game ( - name "Starsky & Hutch (USA) (Beta)" - description "Starsky & Hutch (USA) (Beta)" - rom ( name "Starsky & Hutch (USA) (Beta).gba" size 4231928 crc ab142d2e sha1 861066ddf8b52be194b30cbb70e959989f0a2f76 ) + name "Starsky & Hutch (USA) (Beta) (2003-02-11)" + description "Starsky & Hutch (USA) (Beta) (2003-02-11)" + rom ( name "Starsky & Hutch (USA) (Beta) (2003-02-11).gba" size 4231928 crc ab142d2e sha1 861066ddf8b52be194b30cbb70e959989f0a2f76 ) ) game ( @@ -17004,12 +17484,6 @@ game ( rom ( name "Steel Empire (Europe).gba" size 4194304 crc cb91922e sha1 b280937636a533020bf42591cc246b221a16f94e ) ) -game ( - name "Steven Gerrard's Total Soccer 2002 (Europe) (En,Fr,De,Es,It,Nl)" - description "Steven Gerrard's Total Soccer 2002 (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Steven Gerrard's Total Soccer 2002 (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc b94ddc93 sha1 1f37abe2a70ff0027abe714cb4cd93f168925753 flags verified ) -) - game ( name "Strawberry Shortcake - Ice Cream Island - Riding Camp (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" description "Strawberry Shortcake - Ice Cream Island - Riding Camp (Europe) (En,Fr,De,Es,It,Nl,Pt,Da)" @@ -17076,6 +17550,12 @@ game ( rom ( name "Street Racing Syndicate (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc ac24888b sha1 0536c9d6b0732337eaa6764d918f3b314b96c063 ) ) +game ( + name "Strike Force Hydra (Europe)" + description "Strike Force Hydra (Europe)" + rom ( name "Strike Force Hydra (Europe).gba" size 4194304 crc 277d2c89 sha1 4203315be9e7ce1801cddf294cd18e98c9c9e8b0 ) +) + game ( name "Strike Force Hydra (USA)" description "Strike Force Hydra (USA)" @@ -17083,9 +17563,9 @@ game ( ) game ( - name "Strike Force Hydra (Europe)" - description "Strike Force Hydra (Europe)" - rom ( name "Strike Force Hydra (Europe).gba" size 4194304 crc 277d2c89 sha1 4203315be9e7ce1801cddf294cd18e98c9c9e8b0 ) + name "Stuart Little 2 (Europe) (Rev 1)" + description "Stuart Little 2 (Europe) (Rev 1)" + rom ( name "Stuart Little 2 (Europe) (Rev 1).gba" size 8388608 crc 34e4f8c5 sha1 1435574b92777a633cec0722300601dcbb5f84ce ) ) game ( @@ -17100,12 +17580,6 @@ game ( rom ( name "Stuart Little 2 (France).gba" size 8388608 crc 0827d896 sha1 59ab956ef920bdf2a75b36448f557df8538d558a ) ) -game ( - name "Stuart Little 2 (Europe) (Rev 1)" - description "Stuart Little 2 (Europe) (Rev 1)" - rom ( name "Stuart Little 2 (Europe) (Rev 1).gba" size 8388608 crc 34e4f8c5 sha1 1435574b92777a633cec0722300601dcbb5f84ce ) -) - game ( name "Stuntman (Europe) (En,Fr,De,Es,It)" description "Stuntman (Europe) (En,Fr,De,Es,It)" @@ -17205,7 +17679,7 @@ game ( game ( name "Super Bust-A-Move (Europe) (En,Fr,De,Es,It)" description "Super Bust-A-Move (Europe) (En,Fr,De,Es,It)" - rom ( name "Super Bust-A-Move (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6bfd2915 sha1 e4dd4bb3691444fff595a926b2c06313f2e69751 ) + rom ( name "Super Bust-A-Move (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 6bfd2915 sha1 e4dd4bb3691444fff595a926b2c06313f2e69751 flags verified ) ) game ( @@ -17388,6 +17862,12 @@ game ( rom ( name "Super Mario Advance 3 - Yoshi's Island + Mario Brothers (Japan) (Virtual Console).gba" size 4194304 crc 10f9eda4 sha1 fa7486b4721925074ba1fde9b800ef85a5b5954d ) ) +game ( + name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 2) (Switch Online)" + description "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 2) (Switch Online)" + rom ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 2) (Switch Online).gba" size 8388608 crc aa312980 sha1 b65217bb411bf1e9aff50bf0940c4a0021789f59 ) +) + game ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 2)" description "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan) (Rev 2)" @@ -17409,7 +17889,7 @@ game ( game ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan)" description "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan)" - rom ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan).gba" size 4194304 crc f3c87306 sha1 19f7928bc4ffd733d71884dae9ad9b7f4007d38d ) + rom ( name "Super Mario Advance 4 - Super Mario 3 + Mario Brothers (Japan).gba" size 4194304 crc f3c87306 sha1 19f7928bc4ffd733d71884dae9ad9b7f4007d38d flags verified ) ) game ( @@ -17448,6 +17928,30 @@ game ( rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1) (Virtual Console).gba" size 8388608 crc d4f45b01 sha1 00667ce3da4bfee3182c4445ac2f5483870be97c flags verified ) ) +game ( + name "Super Mario Advance 4 - Super Mario Bros. 3 (USA) (Rev 1) (Switch Online)" + description "Super Mario Advance 4 - Super Mario Bros. 3 (USA) (Rev 1) (Switch Online)" + rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (USA) (Rev 1) (Switch Online).gba" size 8388608 crc 22e12d0e sha1 82fa5a6cf09415c2e262931488841b78a524e2c3 flags verified ) +) + +game ( + name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1) (Switch Online)" + description "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1) (Switch Online)" + rom ( name "Super Mario Advance 4 - Super Mario Bros. 3 (Europe) (En,Fr,De,Es,It) (Rev 1) (Switch Online).gba" size 8388608 crc e3847e32 sha1 cdb79f7926fb61ee7f13ee4cbd61ebe3fb01ba69 flags verified ) +) + +game ( + name "Super Mario Ball (Europe) (Virtual Console)" + description "Super Mario Ball (Europe) (Virtual Console)" + rom ( name "Super Mario Ball (Europe) (Virtual Console).gba" size 8388608 crc 3b15e886 sha1 e3ee63bf92340a50085cb905e167c03f3c60b72a ) +) + +game ( + name "Super Mario Ball (Japan) (Demo) (Kiosk, GameCube)" + description "Super Mario Ball (Japan) (Demo) (Kiosk, GameCube)" + rom ( name "Super Mario Ball (Japan) (Demo) (Kiosk, GameCube).gba" size 8388608 crc 65b1d9cb sha1 f8a356c0ba5e216c8ba408474fd74553d284b9b8 flags verified ) +) + game ( name "Super Mario Ball (Japan) (Virtual Console)" description "Super Mario Ball (Japan) (Virtual Console)" @@ -17466,18 +17970,6 @@ game ( rom ( name "Super Mario Ball (Europe).gba" size 8388608 crc 3b035681 sha1 d53fbc63e08c15bfdc045b5664fe24e8e2718469 flags verified ) ) -game ( - name "Super Mario Ball (Europe) (Virtual Console)" - description "Super Mario Ball (Europe) (Virtual Console)" - rom ( name "Super Mario Ball (Europe) (Virtual Console).gba" size 8388608 crc 3b15e886 sha1 e3ee63bf92340a50085cb905e167c03f3c60b72a ) -) - -game ( - name "Super Mario Ball (Japan) (Demo) (Kiosk, GameCube)" - description "Super Mario Ball (Japan) (Demo) (Kiosk, GameCube)" - rom ( name "Super Mario Ball (Japan) (Demo) (Kiosk, GameCube).gba" size 8388608 crc 65b1d9cb sha1 f8a356c0ba5e216c8ba408474fd74553d284b9b8 flags verified ) -) - game ( name "Super Mario Bros. (Japan) (Hot Mario Campaign)" description "Super Mario Bros. (Japan) (Hot Mario Campaign)" @@ -17652,6 +18144,12 @@ game ( rom ( name "Superman Returns - Fortress of Solitude (USA, Europe) (En,Fr,De,Es,It).gba" size 16777216 crc 68215047 sha1 1ff9d19032466227ae7aaebb0161c531aaf60428 ) ) +game ( + name "Superman Returns - Fortress of Solitude (USA, Europe) (Beta)" + description "Superman Returns - Fortress of Solitude (USA, Europe) (Beta)" + rom ( name "Superman Returns - Fortress of Solitude (USA, Europe) (Beta).gba" size 16777216 crc a0fb8e93 sha1 fd4585fc39ef54e1eb901e463d8e6d45ab40fccf ) +) + game ( name "Surf's Up (USA) (En,Fr,Es)" description "Surf's Up (USA) (En,Fr,Es)" @@ -17670,6 +18168,12 @@ game ( rom ( name "Surf's Up (Europe) (En,Fr,Es).gba" size 8388608 crc 317326b0 sha1 b0a2ba2a7d042cc9426ec1abdbd912613c4ae191 ) ) +game ( + name "Sushi the Cat (World) (Aftermarket) (Unl)" + description "Sushi the Cat (World) (Aftermarket) (Unl)" + rom ( name "Sushi the Cat (World) (Aftermarket) (Unl).gba" size 540296 crc 6f019a88 sha1 f6d523a073c21639e15d615947167bba3871c67a ) +) + game ( name "Sutakomi - Star Communicator (Japan)" description "Sutakomi - Star Communicator (Japan)" @@ -17682,12 +18186,6 @@ game ( rom ( name "Sweet Cookie Pie (Japan).gba" size 4194304 crc 63f45849 sha1 96610003fdb49a14b35aeedf0c8cebf5f80d8e4a ) ) -game ( - name "Sword of Mana (Europe)" - description "Sword of Mana (Europe)" - rom ( name "Sword of Mana (Europe).gba" size 16777216 crc 88e64a8a sha1 129712ce98646c89136cee01902dd20ef6541978 flags verified ) -) - game ( name "Sword of Mana (USA, Australia)" description "Sword of Mana (USA, Australia)" @@ -17706,6 +18204,12 @@ game ( rom ( name "Sword of Mana (Europe) (Es,It).gba" size 16777216 crc 11a0af49 sha1 390dff3ec37d24a5d00165deb17eb64c0ace32b1 ) ) +game ( + name "Sword of Mana (Europe)" + description "Sword of Mana (Europe)" + rom ( name "Sword of Mana (Europe).gba" size 16777216 crc 88e64a8a sha1 129712ce98646c89136cee01902dd20ef6541978 flags verified ) +) + game ( name "Sylvanian Families - Fashion Designer ni Naritai! - Kurumi-risu no Onnanoko (Japan)" description "Sylvanian Families - Fashion Designer ni Naritai! - Kurumi-risu no Onnanoko (Japan)" @@ -17805,7 +18309,7 @@ game ( game ( name "Tales of the World - Narikiri Dungeon 2 (Japan)" description "Tales of the World - Narikiri Dungeon 2 (Japan)" - rom ( name "Tales of the World - Narikiri Dungeon 2 (Japan).gba" size 8388608 crc 231b9fca sha1 2feb4cff9485c68758c1fac847c6eb907e747a01 ) + rom ( name "Tales of the World - Narikiri Dungeon 2 (Japan).gba" size 8388608 crc 231b9fca sha1 2feb4cff9485c68758c1fac847c6eb907e747a01 flags verified ) ) game ( @@ -17934,12 +18438,6 @@ game ( rom ( name "Teenage Mutant Ninja Turtles Double Pack (USA) (En,Fr,De,Es,It).gba" size 16777216 crc 176a42e5 sha1 15cbff45ce0cb35f3e6a6059ada2710f0cec05c3 ) ) -game ( - name "Tekken Advance (Europe)" - description "Tekken Advance (Europe)" - rom ( name "Tekken Advance (Europe).gba" size 8388608 crc 4628c1b8 sha1 0a8665fe4e1f33427f710793db2937485a1c9418 flags verified ) -) - game ( name "Tekken Advance (Japan)" description "Tekken Advance (Japan)" @@ -17952,6 +18450,12 @@ game ( rom ( name "Tekken Advance (USA).gba" size 8388608 crc c59ea73b sha1 8b21cd57cacf172f963dfc7ead4fa127a8a63870 ) ) +game ( + name "Tekken Advance (Europe)" + description "Tekken Advance (Europe)" + rom ( name "Tekken Advance (Europe).gba" size 8388608 crc 4628c1b8 sha1 0a8665fe4e1f33427f710793db2937485a1c9418 flags verified ) +) + game ( name "Ten Pin Alley 2 (USA)" description "Ten Pin Alley 2 (USA)" @@ -18018,6 +18522,12 @@ game ( rom ( name "Tetris Worlds (Europe) (En,Es,It).gba" size 4194304 crc 4a834fc2 sha1 2de4d4c3d239b2e56ad4cc3000bb1ad2fdddd987 ) ) +game ( + name "Tetris Worlds (Japan) (Rev 1)" + description "Tetris Worlds (Japan) (Rev 1)" + rom ( name "Tetris Worlds (Japan) (Rev 1).gba" size 4194304 crc fcf2d471 sha1 be44036e39f95fb9feb93630720d46570ba1a42f ) +) + game ( name "Tetris Worlds (USA)" description "Tetris Worlds (USA)" @@ -18037,9 +18547,9 @@ game ( ) game ( - name "Tetris Worlds (Japan) (Rev 1)" - description "Tetris Worlds (Japan) (Rev 1)" - rom ( name "Tetris Worlds (Japan) (Rev 1).gba" size 4194304 crc fcf2d471 sha1 be44036e39f95fb9feb93630720d46570ba1a42f ) + name "Texas Hold 'em Poker (USA)" + description "Texas Hold 'em Poker (USA)" + rom ( name "Texas Hold 'em Poker (USA).gba" size 4194304 crc 78b59aac sha1 5fcc9958210d8bde94a429516b15ca669427fe6d ) ) game ( @@ -18048,12 +18558,6 @@ game ( rom ( name "Texas Hold 'em Poker (Europe) (Rev 1).gba" size 4194304 crc 1a13df6b sha1 f6d018d9174bf04fd8c90b3173570391f2d11b19 ) ) -game ( - name "Texas Hold 'em Poker (USA, Europe)" - description "Texas Hold 'em Poker (USA, Europe)" - rom ( name "Texas Hold 'em Poker (USA, Europe).gba" size 4194304 crc 78b59aac sha1 5fcc9958210d8bde94a429516b15ca669427fe6d ) -) - game ( name "TG Rally (Europe)" description "TG Rally (Europe)" @@ -18099,7 +18603,7 @@ game ( game ( name "Three-in-One Pack - Sorry! + Aggravation + Scrabble Junior (USA)" description "Three-in-One Pack - Sorry! + Aggravation + Scrabble Junior (USA)" - rom ( name "Three-in-One Pack - Sorry! + Aggravation + Scrabble Junior (USA).gba" size 4194304 crc 111eb61a sha1 cbc5bb55d4951e884e65ea2cab36957ee51aaadb ) + rom ( name "Three-in-One Pack - Sorry! + Aggravation + Scrabble Junior (USA).gba" size 4194304 crc 111eb61a sha1 cbc5bb55d4951e884e65ea2cab36957ee51aaadb flags verified ) ) game ( @@ -18150,12 +18654,6 @@ game ( rom ( name "Tim Burton's The Nightmare Before Christmas - The Pumpkin King (USA, Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 3c247c14 sha1 8e713fa3e3cc5aa8c1836fba9d81bbf80de20638 ) ) -game ( - name "Tiny Chao Garden (USA) (Ja) (Phantasy Star Online Episode I & II)" - description "Tiny Chao Garden (USA) (Ja) (Phantasy Star Online Episode I & II)" - rom ( name "Tiny Chao Garden (USA) (Ja) (Phantasy Star Online Episode I & II).gba" size 182840 crc c523504f sha1 55c9812e2164a618575c6dcd669fd993b60585f5 flags verified ) -) - game ( name "Tiny Toon Adventures - Buster's Bad Dream (Europe) (En,Fr,De,Es,It)" description "Tiny Toon Adventures - Buster's Bad Dream (Europe) (En,Fr,De,Es,It)" @@ -18249,7 +18747,7 @@ game ( game ( name "Tokyo Xtreme Racer Advance (Europe) (En,Fr,De,Es,It)" description "Tokyo Xtreme Racer Advance (Europe) (En,Fr,De,Es,It)" - rom ( name "Tokyo Xtreme Racer Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc bd5f5f4c sha1 15a306794efdd64651387c1447ae4713892e4b87 ) + rom ( name "Tokyo Xtreme Racer Advance (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc bd5f5f4c sha1 15a306794efdd64651387c1447ae4713892e4b87 flags verified ) ) game ( @@ -18411,7 +18909,7 @@ game ( game ( name "Tony Hawk's Pro Skater 3 (France)" description "Tony Hawk's Pro Skater 3 (France)" - rom ( name "Tony Hawk's Pro Skater 3 (France).gba" size 8388608 crc 8d132067 sha1 62ba6f28f5bbd8fe42ecabecdcff4d6b96ae4f21 ) + rom ( name "Tony Hawk's Pro Skater 3 (France).gba" size 8388608 crc 8d132067 sha1 62ba6f28f5bbd8fe42ecabecdcff4d6b96ae4f21 flags verified ) ) game ( @@ -18435,7 +18933,7 @@ game ( game ( name "Tony Hawk's Underground 2 (USA, Europe)" description "Tony Hawk's Underground 2 (USA, Europe)" - rom ( name "Tony Hawk's Underground 2 (USA, Europe).gba" size 8388608 crc bf864083 sha1 c684d839c32515a99e62b183b607e2259120cfc9 ) + rom ( name "Tony Hawk's Underground 2 (USA, Europe).gba" size 8388608 crc bf864083 sha1 c684d839c32515a99e62b183b607e2259120cfc9 flags verified ) ) game ( @@ -18498,12 +18996,24 @@ game ( rom ( name "Top Spin 2 (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc a8e8618b sha1 192bb233840382e410fd242f6b6bfbd33ab24d38 ) ) +game ( + name "Total Soccer 2002 (Europe) (En,Fr,De,Es,It,Nl)" + description "Total Soccer 2002 (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Total Soccer 2002 (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc b94ddc93 sha1 1f37abe2a70ff0027abe714cb4cd93f168925753 flags verified ) +) + game ( name "Total Soccer Advance (Japan)" description "Total Soccer Advance (Japan)" rom ( name "Total Soccer Advance (Japan).gba" size 4194304 crc 28c3e211 sha1 3a45d03ac6b098b70641c222f684abd13ef02500 ) ) +game ( + name "Total Soccer Manager (Europe) (En,Fr,De,Es,It,Nl)" + description "Total Soccer Manager (Europe) (En,Fr,De,Es,It,Nl)" + rom ( name "Total Soccer Manager (Europe) (En,Fr,De,Es,It,Nl).gba" size 4194304 crc 92f99295 sha1 a870e1321a8ad3317cd695fcc0c713441c25919f ) +) + game ( name "Totally Spies! (Europe) (En,Fr,De,Es,It,Nl)" description "Totally Spies! (Europe) (En,Fr,De,Es,It,Nl)" @@ -18540,6 +19050,12 @@ game ( rom ( name "Tottoko Hamutarou - Hamu-Hamu Sports (Japan) (Demo) (Kiosk, GameCube).gba" size 16777216 crc 7cd6839c sha1 ace1d3587636d17fd9ebfe7a7cfd3ee36bc51b43 flags verified ) ) +game ( + name "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan) (Beta) (2002-05-29)" + description "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan) (Beta) (2002-05-29)" + rom ( name "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan) (Beta) (2002-05-29).gba" size 8388608 crc 782e25ae sha1 3f1a1448db7a48fe99428bb94b7b04382fd67aad ) +) + game ( name "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan)" description "Tottoko Hamutarou 3 - Love Love Daibouken Dechu (Japan)" @@ -18577,15 +19093,15 @@ game ( ) game ( - name "Toyrobo Force (Japan)" - description "Toyrobo Force (Japan)" - rom ( name "Toyrobo Force (Japan).gba" size 4194304 crc 227fc16b sha1 6ef30145099d09cf1a1f2b3bc6618a985dabdaae ) + name "Toy Robo Force (Japan)" + description "Toy Robo Force (Japan)" + rom ( name "Toy Robo Force (Japan).gba" size 4194304 crc 227fc16b sha1 6ef30145099d09cf1a1f2b3bc6618a985dabdaae ) ) game ( - name "Travis Pastrana's Pro MotoX (USA, Europe) (Proto) (2002-12-12)" - description "Travis Pastrana's Pro MotoX (USA, Europe) (Proto) (2002-12-12)" - rom ( name "Travis Pastrana's Pro MotoX (USA, Europe) (Proto) (2002-12-12).gba" size 4194304 crc ecfe5f96 sha1 64e356f495fd58a862f272124798ecf61e20cfb7 ) + name "Travis Pastrana's Pro MotoX (USA) (Proto) (2002-12-12)" + description "Travis Pastrana's Pro MotoX (USA) (Proto) (2002-12-12)" + rom ( name "Travis Pastrana's Pro MotoX (USA) (Proto) (2002-12-12).gba" size 4194304 crc ecfe5f96 sha1 64e356f495fd58a862f272124798ecf61e20cfb7 ) ) game ( @@ -18607,27 +19123,33 @@ game ( ) game ( - name "Tremblay Island (World) (v.1.10) (Aftermarket) (Homebrew)" - description "Tremblay Island (World) (v.1.10) (Aftermarket) (Homebrew)" - rom ( name "Tremblay Island (World) (v.1.10) (Aftermarket) (Homebrew).gba" size 16239516 crc ce85ba07 sha1 b09b600bfc222c2d92829d8883feab700b013953 ) + name "Tremblay Island (World) (En) (v1.1) (Aftermarket) (Unl)" + description "Tremblay Island (World) (En) (v1.1) (Aftermarket) (Unl)" + rom ( name "Tremblay Island (World) (En) (v1.1) (Aftermarket) (Unl).gba" size 16239516 crc ce85ba07 sha1 b09b600bfc222c2d92829d8883feab700b013953 ) ) game ( - name "Tremblay Island (World) (v.1.10) (Solid State Version) (Aftermarket) (Homebrew)" - description "Tremblay Island (World) (v.1.10) (Solid State Version) (Aftermarket) (Homebrew)" - rom ( name "Tremblay Island (World) (v.1.10) (Solid State Version) (Aftermarket) (Homebrew).gba" size 16229600 crc bd57344d sha1 a2fcfe94c9b8b0feff31c1245c8b033222c9f668 ) + name "Tremblay Island (World) (En) (v1.1) (Solid State Version) (Aftermarket) (Unl)" + description "Tremblay Island (World) (En) (v1.1) (Solid State Version) (Aftermarket) (Unl)" + rom ( name "Tremblay Island (World) (En) (v1.1) (Solid State Version) (Aftermarket) (Unl).gba" size 16229600 crc bd57344d sha1 a2fcfe94c9b8b0feff31c1245c8b033222c9f668 ) ) game ( - name "Tremblay Island (World) (Fr) (v.1.10) (Solid State Version) (Aftermarket) (Homebrew)" - description "Tremblay Island (World) (Fr) (v.1.10) (Solid State Version) (Aftermarket) (Homebrew)" - rom ( name "Tremblay Island (World) (Fr) (v.1.10) (Solid State Version) (Aftermarket) (Homebrew).gba" size 16204024 crc fa43669e sha1 a57392fa7cee61913b20a840fe8b2ee27f11d808 ) + name "Tremblay Island (World) (Fr) (v1.1) (Solid State Version) (Aftermarket) (Unl)" + description "Tremblay Island (World) (Fr) (v1.1) (Solid State Version) (Aftermarket) (Unl)" + rom ( name "Tremblay Island (World) (Fr) (v1.1) (Solid State Version) (Aftermarket) (Unl).gba" size 16204024 crc fa43669e sha1 a57392fa7cee61913b20a840fe8b2ee27f11d808 ) ) game ( - name "Tremblay Island (World) (Kickstarter Edition) (Aftermarket) (Homebrew)" - description "Tremblay Island (World) (Kickstarter Edition) (Aftermarket) (Homebrew)" - rom ( name "Tremblay Island (World) (Kickstarter Edition) (Aftermarket) (Homebrew).gba" size 16777216 crc ff5d64ab sha1 645ab8d4dacb6666d8eb549d491f77d8cd63ce97 ) + name "Tremblay Island (World) (En) (v1.1) (Kickstarter Edition) (Aftermarket) (Unl)" + description "Tremblay Island (World) (En) (v1.1) (Kickstarter Edition) (Aftermarket) (Unl)" + rom ( name "Tremblay Island (World) (En) (v1.1) (Kickstarter Edition) (Aftermarket) (Unl).gba" size 16777216 crc ff5d64ab sha1 645ab8d4dacb6666d8eb549d491f77d8cd63ce97 ) +) + +game ( + name "Tremblay Island (World) (Aftermarket) (Unl)" + description "Tremblay Island (World) (Aftermarket) (Unl)" + rom ( name "Tremblay Island (World) (Aftermarket) (Unl).gba" size 16225608 crc 95503690 sha1 634ea6be3df5ebd85c9c60871e34fc3c72ae5140 ) ) game ( @@ -18696,6 +19218,12 @@ game ( rom ( name "Tsuukin Hitofude (Japan) (Virtual Console).gba" size 4194304 crc f4c7a95b sha1 906dbf246cb40954fc27942763048bc09783b1f8 ) ) +game ( + name "Tsuukin Hitofude (Japan) (Beta)" + description "Tsuukin Hitofude (Japan) (Beta)" + rom ( name "Tsuukin Hitofude (Japan) (Beta).gba" size 1048576 crc 9542e247 sha1 24b4be7f296fce5eae93d969eb02831951f00b7b ) +) + game ( name "Turbo Turtle Adventure (USA)" description "Turbo Turtle Adventure (USA)" @@ -18942,6 +19470,18 @@ game ( rom ( name "Unglaublichen, Die (Germany).gba" size 8388608 crc bdc06e57 sha1 6bc89e6aa6cd251d56fe86e520b08cadf20ca4f4 ) ) +game ( + name "Uno - Free Fall (USA)" + description "Uno - Free Fall (USA)" + rom ( name "Uno - Free Fall (USA).gba" size 4194304 crc 19fcc78e sha1 2dacf03965ee248d414d385594cc919f896f032e ) +) + +game ( + name "Uno - Free Fall (Europe) (En,Fr,De,Es,It)" + description "Uno - Free Fall (Europe) (En,Fr,De,Es,It)" + rom ( name "Uno - Free Fall (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 414ea9f4 sha1 2ad8bdfc425f9426296c03acd433b296e40eb72e ) +) + game ( name "Uno 52 (USA)" description "Uno 52 (USA)" @@ -18954,18 +19494,6 @@ game ( rom ( name "Uno 52 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 315360d0 sha1 f85709ec7a97c8b40504f2097497bd961531272d ) ) -game ( - name "Uno Free Fall (USA)" - description "Uno Free Fall (USA)" - rom ( name "Uno Free Fall (USA).gba" size 4194304 crc 19fcc78e sha1 2dacf03965ee248d414d385594cc919f896f032e ) -) - -game ( - name "Uno Free Fall (Europe) (En,Fr,De,Es,It)" - description "Uno Free Fall (Europe) (En,Fr,De,Es,It)" - rom ( name "Uno Free Fall (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 414ea9f4 sha1 2ad8bdfc425f9426296c03acd433b296e40eb72e ) -) - game ( name "Urban Yeti! (USA, Europe)" description "Urban Yeti! (USA, Europe)" @@ -19051,9 +19579,9 @@ game ( ) game ( - name "Viewpoint (World) (Tech Demo)" - description "Viewpoint (World) (Tech Demo)" - rom ( name "Viewpoint (World) (Tech Demo).gba" size 2097152 crc 7ad65e4b sha1 8fdcc5c207593cb196cea8416bb14bb45db37434 ) + name "Viewpoint (Europe) (Demo)" + description "Viewpoint (Europe) (Demo)" + rom ( name "Viewpoint (Europe) (Demo).gba" size 2097152 crc 7ad65e4b sha1 8fdcc5c207593cb196cea8416bb14bb45db37434 ) ) game ( @@ -19128,6 +19656,12 @@ game ( rom ( name "Wagamama Fairy Mirumo de Pon! - Yume no Kakera (Japan).gba" size 8388608 crc a606c803 sha1 0429693de0ff6e020b01807047dbb07b70b42529 ) ) +game ( + name "Waimanu - Grinding Blocks Adventure (World) (Homebrew)" + description "Waimanu - Grinding Blocks Adventure (World) (Homebrew)" + rom ( name "Waimanu - Grinding Blocks Adventure (World) (Homebrew).gba" size 1739504 crc 0fe153c5 sha1 c4ce156b04fb257875bc5f539f3d64accbc08451 ) +) + game ( name "Wakeboarding Unleashed Featuring Shaun Murray (Europe)" description "Wakeboarding Unleashed Featuring Shaun Murray (Europe)" @@ -19182,12 +19716,6 @@ game ( rom ( name "Wanwan Meitantei (Japan).gba" size 8388608 crc 5f41c9fe sha1 d438e3b030a814818ed7e96777ac3e46043922f9 ) ) -game ( - name "Wario Land 4 (USA, Europe) (Virtual Console)" - description "Wario Land 4 (USA, Europe) (Virtual Console)" - rom ( name "Wario Land 4 (USA, Europe) (Virtual Console).gba" size 8388608 crc 8bb73d8a sha1 ed643151b8cc9749a490cab6bae26104e1652089 flags verified ) -) - game ( name "Wario Land 4 (USA, Europe)" description "Wario Land 4 (USA, Europe)" @@ -19195,9 +19723,9 @@ game ( ) game ( - name "Wario Land Advance - Youki no Otakara (Japan)" - description "Wario Land Advance - Youki no Otakara (Japan)" - rom ( name "Wario Land Advance - Youki no Otakara (Japan).gba" size 8388608 crc f56ebb7a sha1 a01de1f2e69ec8aa9715ed0d0fbb263372b71e12 flags verified ) + name "Wario Land 4 (USA, Europe) (Virtual Console)" + description "Wario Land 4 (USA, Europe) (Virtual Console)" + rom ( name "Wario Land 4 (USA, Europe) (Virtual Console).gba" size 8388608 crc 8bb73d8a sha1 ed643151b8cc9749a490cab6bae26104e1652089 flags verified ) ) game ( @@ -19207,9 +19735,21 @@ game ( ) game ( - name "WarioWare - Twisted! (USA)" - description "WarioWare - Twisted! (USA)" - rom ( name "WarioWare - Twisted! (USA).gba" size 16777216 crc cb4e844b sha1 f0102d0d6f7596fe853d5d0a94682718278e083a flags verified ) + name "Wario Land Advance - Youki no Otakara (Japan)" + description "Wario Land Advance - Youki no Otakara (Japan)" + rom ( name "Wario Land Advance - Youki no Otakara (Japan).gba" size 8388608 crc f56ebb7a sha1 a01de1f2e69ec8aa9715ed0d0fbb263372b71e12 flags verified ) +) + +game ( + name "WarioWare - Twisted! (USA, Australia)" + description "WarioWare - Twisted! (USA, Australia)" + rom ( name "WarioWare - Twisted! (USA, Australia).gba" size 16777216 crc cb4e844b sha1 f0102d0d6f7596fe853d5d0a94682718278e083a flags verified ) +) + +game ( + name "WarioWare, Inc. - Mega Microgame$! (USA)" + description "WarioWare, Inc. - Mega Microgame$! (USA)" + rom ( name "WarioWare, Inc. - Mega Microgame$! (USA).gba" size 8388608 crc 785d8b8c sha1 3f556448d290fa5406d6ed367fee16cc02387ad3 flags verified ) ) game ( @@ -19225,9 +19765,9 @@ game ( ) game ( - name "WarioWare, Inc. - Mega Microgame$! (USA)" - description "WarioWare, Inc. - Mega Microgame$! (USA)" - rom ( name "WarioWare, Inc. - Mega Microgame$! (USA).gba" size 8388608 crc 785d8b8c sha1 3f556448d290fa5406d6ed367fee16cc02387ad3 flags verified ) + name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It) (Virtual Console)" + description "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It) (Virtual Console)" + rom ( name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It) (Virtual Console).gba" size 8388608 crc 1fe34e43 sha1 dca921c60b3686be6b3a5feeec7a4f37a921aee3 ) ) game ( @@ -19236,12 +19776,6 @@ game ( rom ( name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc 500ca178 sha1 aad81e722aa88f98913c0354e559f845c4689cce flags verified ) ) -game ( - name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It) (Virtual Console)" - description "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It) (Virtual Console)" - rom ( name "WarioWare, Inc. - Minigame Mania (Europe) (En,Fr,De,Es,It) (Virtual Console).gba" size 8388608 crc 1fe34e43 sha1 dca921c60b3686be6b3a5feeec7a4f37a921aee3 ) -) - game ( name "Weekend Miljonairs (Netherlands)" description "Weekend Miljonairs (Netherlands)" @@ -19374,18 +19908,18 @@ game ( rom ( name "Winning Post for Game Boy Advance (Japan) (Rev 2).gba" size 4194304 crc 9fb4af0a sha1 9151cf54475c4f773bdd9ab86a42d3e1ba462afa ) ) -game ( - name "Winning Post for Game Boy Advance (Japan) (Rev 1)" - description "Winning Post for Game Boy Advance (Japan) (Rev 1)" - rom ( name "Winning Post for Game Boy Advance (Japan) (Rev 1).gba" size 4194304 crc f6180af5 sha1 0f395a384b9db2415196edc2f911ccc67eb5e038 ) -) - game ( name "Winning Post for Game Boy Advance (Japan)" description "Winning Post for Game Boy Advance (Japan)" rom ( name "Winning Post for Game Boy Advance (Japan).gba" size 4194304 crc 5ada60f6 sha1 cc7e9c2a9e1df985aed3dc4a018c93140d7a1b2c ) ) +game ( + name "Winning Post for Game Boy Advance (Japan) (Rev 1)" + description "Winning Post for Game Boy Advance (Japan) (Rev 1)" + rom ( name "Winning Post for Game Boy Advance (Japan) (Rev 1).gba" size 4194304 crc f6180af5 sha1 0f395a384b9db2415196edc2f911ccc67eb5e038 ) +) + game ( name "Winter Sports (Europe) (En,Fr,De,Es,It)" description "Winter Sports (Europe) (En,Fr,De,Es,It)" @@ -19417,9 +19951,15 @@ game ( ) game ( - name "Wizardry Summoner (Japan)" - description "Wizardry Summoner (Japan)" - rom ( name "Wizardry Summoner (Japan).gba" size 4194304 crc 71695a71 sha1 c9ba4742d494d61a215f6e8068fdaeed12d19cdc ) + name "With the Last Moonbeam (World) (v1.0.0) (Aftermarket) (Unl)" + description "With the Last Moonbeam (World) (v1.0.0) (Aftermarket) (Unl)" + rom ( name "With the Last Moonbeam (World) (v1.0.0) (Aftermarket) (Unl).gba" size 1449956 crc 4ffa611d sha1 89bbeb3fbce1533acf2f2113642ebe2a4f9f79a8 ) +) + +game ( + name "With the Last Moonbeam (World) (v1.0.1) (Aftermarket) (Unl)" + description "With the Last Moonbeam (World) (v1.0.1) (Aftermarket) (Unl)" + rom ( name "With the Last Moonbeam (World) (v1.0.1) (Aftermarket) (Unl).gba" size 1449956 crc 27055186 sha1 b9ce91d55870e07434509f6e2e91c2f90b4afc97 ) ) game ( @@ -19428,6 +19968,12 @@ game ( rom ( name "Wizardry Summoner (Japan) (Rev 1).gba" size 4194304 crc b3c77a61 sha1 c4ddb35319b8ed0f2e3d281ad93e42a0db757cd5 flags verified ) ) +game ( + name "Wizardry Summoner (Japan)" + description "Wizardry Summoner (Japan)" + rom ( name "Wizardry Summoner (Japan).gba" size 4194304 crc 71695a71 sha1 c9ba4742d494d61a215f6e8068fdaeed12d19cdc ) +) + game ( name "Wolfenstein 3D (USA, Europe)" description "Wolfenstein 3D (USA, Europe)" @@ -19495,15 +20041,9 @@ game ( ) game ( - name "World Reborn (World) (Aftermarket) (Unl)" - description "World Reborn (World) (Aftermarket) (Unl)" - rom ( name "World Reborn (World) (Aftermarket) (Unl).gba" size 4194304 crc eefb32ff sha1 c7ec2f8d7d3dec40a893cdfe2a41a8ed43ed71c4 ) -) - -game ( - name "World Tennis Stars (Europe)" - description "World Tennis Stars (Europe)" - rom ( name "World Tennis Stars (Europe).gba" size 4194304 crc b5830f5f sha1 2a93449943e85b7c5d75d0d7a9e1d8ad67c7a706 ) + name "World Reborn (USA) (Aftermarket) (Unl)" + description "World Reborn (USA) (Aftermarket) (Unl)" + rom ( name "World Reborn (USA) (Aftermarket) (Unl).gba" size 4194304 crc eefb32ff sha1 c7ec2f8d7d3dec40a893cdfe2a41a8ed43ed71c4 ) ) game ( @@ -19512,24 +20052,30 @@ game ( rom ( name "World Tennis Stars (USA).gba" size 4194304 crc 036e30b0 sha1 c668815a2ccf0bc6c3816d0947218661437449bc ) ) +game ( + name "World Tennis Stars (Europe)" + description "World Tennis Stars (Europe)" + rom ( name "World Tennis Stars (Europe).gba" size 4194304 crc b5830f5f sha1 2a93449943e85b7c5d75d0d7a9e1d8ad67c7a706 ) +) + +game ( + name "Worms - World Party (Europe) (En,Fr,De,Es,It)" + description "Worms - World Party (Europe) (En,Fr,De,Es,It)" + rom ( name "Worms - World Party (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 8ee32cbe sha1 5e0abe3d94d1489fadebe897df1ed5a5c0212901 ) +) + +game ( + name "Worms - World Party (USA) (En,Fr,De,Es,It)" + description "Worms - World Party (USA) (En,Fr,De,Es,It)" + rom ( name "Worms - World Party (USA) (En,Fr,De,Es,It).gba" size 4194304 crc e8789c18 sha1 7b078976d9056aba7f81bb1ff33e5a36357f5f0b ) +) + game ( name "Worms Blast (Europe) (En,Fr,De,Es,It)" description "Worms Blast (Europe) (En,Fr,De,Es,It)" rom ( name "Worms Blast (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 5223f5aa sha1 0da4ff24b61ae8b6d67ef59377770fd958517f2f ) ) -game ( - name "Worms World Party (Europe) (En,Fr,De,Es,It)" - description "Worms World Party (Europe) (En,Fr,De,Es,It)" - rom ( name "Worms World Party (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 8ee32cbe sha1 5e0abe3d94d1489fadebe897df1ed5a5c0212901 ) -) - -game ( - name "Worms World Party (USA) (En,Fr,De,Es,It)" - description "Worms World Party (USA) (En,Fr,De,Es,It)" - rom ( name "Worms World Party (USA) (En,Fr,De,Es,It).gba" size 4194304 crc e8789c18 sha1 7b078976d9056aba7f81bb1ff33e5a36357f5f0b ) -) - game ( name "WTA Tour Tennis (USA)" description "WTA Tour Tennis (USA)" @@ -19551,13 +20097,7 @@ game ( game ( name "WWE - Survivor Series (USA, Europe)" description "WWE - Survivor Series (USA, Europe)" - rom ( name "WWE - Survivor Series (USA, Europe).gba" size 4194304 crc 6694f94d sha1 bb61e289f2a09e7ce0e193267430dbc6f5583a49 ) -) - -game ( - name "WWF - Road to WrestleMania (USA, Europe) (Beta)" - description "WWF - Road to WrestleMania (USA, Europe) (Beta)" - rom ( name "WWF - Road to WrestleMania (USA, Europe) (Beta).gba" size 4194304 crc 8314421b sha1 13c1965b62849873738417830e142182782430fe ) + rom ( name "WWE - Survivor Series (USA, Europe).gba" size 4194304 crc 6694f94d sha1 bb61e289f2a09e7ce0e193267430dbc6f5583a49 flags verified ) ) game ( @@ -19566,24 +20106,30 @@ game ( rom ( name "WWF - Road to WrestleMania (USA, Europe).gba" size 4194304 crc 8d3b116e sha1 e9334fd4b7a8acf2256a8e2e97f0ab3dd91d6abb ) ) +game ( + name "WWF - Road to WrestleMania (USA, Europe) (Beta)" + description "WWF - Road to WrestleMania (USA, Europe) (Beta)" + rom ( name "WWF - Road to WrestleMania (USA, Europe) (Beta).gba" size 4194304 crc 8314421b sha1 13c1965b62849873738417830e142182782430fe ) +) + game ( name "X Zhan Jing (Taiwan) (Unl)" description "X Zhan Jing (Taiwan) (Unl)" rom ( name "X Zhan Jing (Taiwan) (Unl).gba" size 33554432 crc 652a2ebe sha1 a35c891af070819fd14e0704984197c8e04ae127 ) ) -game ( - name "X-Bladez - Inline Skater (Europe)" - description "X-Bladez - Inline Skater (Europe)" - rom ( name "X-Bladez - Inline Skater (Europe).gba" size 4194304 crc c05f9907 sha1 8a5dc506fd6e000116be2ca923a056bc15d5b553 ) -) - game ( name "X-Bladez - Inline Skater (USA)" description "X-Bladez - Inline Skater (USA)" rom ( name "X-Bladez - Inline Skater (USA).gba" size 4194304 crc 09fdd665 sha1 a8354a51738c6b28660ab74acc7f8445a9a570a1 ) ) +game ( + name "X-Bladez - Inline Skater (Europe)" + description "X-Bladez - Inline Skater (Europe)" + rom ( name "X-Bladez - Inline Skater (Europe).gba" size 4194304 crc c05f9907 sha1 8a5dc506fd6e000116be2ca923a056bc15d5b553 ) +) + game ( name "X-Man - Armour of Might (Russia) (Unl)" description "X-Man - Armour of Might (Russia) (Unl)" @@ -19770,6 +20316,12 @@ game ( rom ( name "Yu-Gi-Oh! - Destiny Board Traveler (Europe) (En,Fr,De,Es,It).gba" size 16777216 crc ae1a8e9d sha1 96fd0e583ab49258b194f578e29e9a5d55122b50 ) ) +game ( + name "Yu-Gi-Oh! - Dungeon Dice Monsters (Europe) (En,Fr,De,Es,It)" + description "Yu-Gi-Oh! - Dungeon Dice Monsters (Europe) (En,Fr,De,Es,It)" + rom ( name "Yu-Gi-Oh! - Dungeon Dice Monsters (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc ee317f69 sha1 3ded1227698fbdb2ba47f03025cd1934fc184b99 flags verified ) +) + game ( name "Yu-Gi-Oh! - Dungeon Dice Monsters (Japan)" description "Yu-Gi-Oh! - Dungeon Dice Monsters (Japan)" @@ -19782,12 +20334,6 @@ game ( rom ( name "Yu-Gi-Oh! - Dungeon Dice Monsters (USA) (En,Es).gba" size 8388608 crc 8b5e0a27 sha1 fdd69455a072b2f74e6c5c50b96daa0438156b27 flags verified ) ) -game ( - name "Yu-Gi-Oh! - Dungeon Dice Monsters (Europe) (En,Fr,De,Es,It)" - description "Yu-Gi-Oh! - Dungeon Dice Monsters (Europe) (En,Fr,De,Es,It)" - rom ( name "Yu-Gi-Oh! - Dungeon Dice Monsters (Europe) (En,Fr,De,Es,It).gba" size 8388608 crc ee317f69 sha1 3ded1227698fbdb2ba47f03025cd1934fc184b99 flags verified ) -) - game ( name "Yu-Gi-Oh! - Reshef of Destruction (USA)" description "Yu-Gi-Oh! - Reshef of Destruction (USA)" @@ -19887,7 +20433,7 @@ game ( game ( name "Yu-Gi-Oh! Duel Monsters 6 Expert 2 (Japan)" description "Yu-Gi-Oh! Duel Monsters 6 Expert 2 (Japan)" - rom ( name "Yu-Gi-Oh! Duel Monsters 6 Expert 2 (Japan).gba" size 16777216 crc a7054d60 sha1 e5ee6fb7a6a4eb0e33197549fd30f8fe402b595f ) + rom ( name "Yu-Gi-Oh! Duel Monsters 6 Expert 2 (Japan).gba" size 16777216 crc a7054d60 sha1 e5ee6fb7a6a4eb0e33197549fd30f8fe402b595f flags verified ) ) game ( @@ -19941,7 +20487,7 @@ game ( game ( name "Yu-Gi-Oh! GX - Duel Academy (USA)" description "Yu-Gi-Oh! GX - Duel Academy (USA)" - rom ( name "Yu-Gi-Oh! GX - Duel Academy (USA).gba" size 33554432 crc 3b8a00fe sha1 57d6bb789833b62b360072902982d5f1011b3640 ) + rom ( name "Yu-Gi-Oh! GX - Duel Academy (USA).gba" size 33554432 crc 3b8a00fe sha1 57d6bb789833b62b360072902982d5f1011b3640 flags verified ) ) game ( @@ -19995,7 +20541,7 @@ game ( game ( name "Zelda no Densetsu - Fushigi no Boushi (Japan)" description "Zelda no Densetsu - Fushigi no Boushi (Japan)" - rom ( name "Zelda no Densetsu - Fushigi no Boushi (Japan).gba" size 16777216 crc 6ce771a5 sha1 6c5404a1effb17f481f352181d0f1c61a2765c5d ) + rom ( name "Zelda no Densetsu - Fushigi no Boushi (Japan).gba" size 16777216 crc 6ce771a5 sha1 6c5404a1effb17f481f352181d0f1c61a2765c5d flags verified ) ) game ( @@ -20077,9 +20623,9 @@ game ( ) game ( - name "Zidane Football Generation 2002 (Europe) (En,Fr,De,Es,It)" - description "Zidane Football Generation 2002 (Europe) (En,Fr,De,Es,It)" - rom ( name "Zidane Football Generation 2002 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 59e2635f sha1 e18e9e8aabb8844de688ddff8843329f84e470aa ) + name "Zidane - Football Generation 2002 (Europe) (En,Fr,De,Es,It)" + description "Zidane - Football Generation 2002 (Europe) (En,Fr,De,Es,It)" + rom ( name "Zidane - Football Generation 2002 (Europe) (En,Fr,De,Es,It).gba" size 4194304 crc 59e2635f sha1 e18e9e8aabb8844de688ddff8843329f84e470aa ) ) game ( @@ -20089,9 +20635,9 @@ game ( ) game ( - name "Zoids Legacy (USA)" - description "Zoids Legacy (USA)" - rom ( name "Zoids Legacy (USA).gba" size 8388608 crc 302e75f3 sha1 460fa2158606097f6e6f63ce966d2d6ecdd58d70 ) + name "Zoids - Legacy (USA)" + description "Zoids - Legacy (USA)" + rom ( name "Zoids - Legacy (USA).gba" size 8388608 crc 302e75f3 sha1 460fa2158606097f6e6f63ce966d2d6ecdd58d70 ) ) game ( @@ -20118,18 +20664,18 @@ game ( rom ( name "Zoids Saga II (Japan).gba" size 8388608 crc 0c039503 sha1 6014ca7c7af931d62634be4baa992a2fe187413f ) ) -game ( - name "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan)" - description "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan)" - rom ( name "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan).gba" size 16777216 crc 2804e589 sha1 54a4dcdeca2ee9a22559eb104b88586386639097 ) -) - game ( name "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan) (Rev 1)" description "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan) (Rev 1)" rom ( name "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan) (Rev 1).gba" size 16777216 crc 71e2cd01 sha1 1a81843c3070decea4cbca20c4563541400b2437 ) ) +game ( + name "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan)" + description "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan)" + rom ( name "Zoku Bokura no Taiyou - Taiyou Shounen Django (Japan).gba" size 16777216 crc 2804e589 sha1 54a4dcdeca2ee9a22559eb104b88586386639097 ) +) + game ( name "Zone of the Enders - The Fist of Mars (USA)" description "Zone of the Enders - The Fist of Mars (USA)" @@ -20763,10 +21309,10 @@ game ( ) clrmamepro ( - name "Nintendo - Game Boy" - description "Nintendo - Game Boy" - version 20220829-183056 - author "aci68, akubi, Arctic Circle System, Aringon, baldjared, Bent, BigFred, BitLooter, C. V. Reynolds, chillerecke, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, ElBarto, foxe, fuzzball, Gefflon, Hiccup, hking0036, InternalLoss, jimmsu, kazumi213, leekindo, Lesserkuma, Madeline, Money_114, NESBrew12, NGEfreak, nnssxx, norkmetnoil577, NovaAurora, omonim2007, Powerpuff, PPLToast, relax, RetroUprising, rpg2813, sCZther, SonGoku, Tauwasser, togemet2, UnlockerPT, xNo, xuom2" + name "Nintendo - Game Boy Advance (Video)" + description "Nintendo - Game Boy Advance (Video)" + version 20230804-201325 + author "BigFred, C. V. Reynolds, DeadSkullzJr, Hiccup, kazumi213, omonim2007, relax, SonGoku, xuom2" homepage No-Intro url "https://www.no-intro.org" forcenodump required @@ -20777,9 +21323,287 @@ emulator ( ) game ( - name "[BIOS] Nintendo Game Boy Boot ROM (Japan) (En)" - description "[BIOS] Nintendo Game Boy Boot ROM (Japan) (En)" - rom ( name "[BIOS] Nintendo Game Boy Boot ROM (Japan) (En).gb" size 256 crc c2f5cc97 sha1 8bd501e31921e9601788316dbd3ce9833a97bcbc flags verified ) + name "Game Boy Advance Video - All Grown Up! - Volume 1 (USA)" + description "Game Boy Advance Video - All Grown Up! - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - All Grown Up! - Volume 1 (USA).gba" size 33554432 crc ffbd4da9 sha1 02158627fd5a526f848077440182fa92ad87ea3f ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Edition Platinum (France)" + description "Game Boy Advance Video - Cartoon Network Collection - Edition Platinum (France)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Edition Platinum (France).gba" size 33554432 crc fc042f18 sha1 01564b86644cf43f49320e0c05854896f8c60c2f ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Edition Premium (France)" + description "Game Boy Advance Video - Cartoon Network Collection - Edition Premium (France)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Edition Premium (France).gba" size 33554432 crc 58f1cde8 sha1 f63052e2b53c42601f53148bee69f89d9591fbf9 ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Edition Speciale (France)" + description "Game Boy Advance Video - Cartoon Network Collection - Edition Speciale (France)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Edition Speciale (France).gba" size 33554432 crc 71154d42 sha1 73cbdd82640f166737173b0e8197d771d7906a91 ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Limited Edition (USA)" + description "Game Boy Advance Video - Cartoon Network Collection - Limited Edition (USA)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Limited Edition (USA).gba" size 33554432 crc 5d918b2d sha1 ac63a7691774bde6eaad4c2c5c4d305e7cc0535a ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Platinum Edition (USA, Europe)" + description "Game Boy Advance Video - Cartoon Network Collection - Platinum Edition (USA, Europe)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Platinum Edition (USA, Europe).gba" size 33554432 crc 6443554b sha1 0cf9b536f87cb21f738bd7552e95bd114b0f0b2e ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Premium Edition (USA, Europe)" + description "Game Boy Advance Video - Cartoon Network Collection - Premium Edition (USA, Europe)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Premium Edition (USA, Europe).gba" size 33554432 crc f2825729 sha1 d0fe380fcdf5b1bb99188ed95c8c3272cbb65ce8 flags verified ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Special Edition (USA) (Rev 5)" + description "Game Boy Advance Video - Cartoon Network Collection - Special Edition (USA) (Rev 5)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Special Edition (USA) (Rev 5).gba" size 33554432 crc 1baf372d sha1 86f257c7b8d8feaee0a7e7dd5f5ba48053fd633e flags verified ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Special Edition (USA, Europe)" + description "Game Boy Advance Video - Cartoon Network Collection - Special Edition (USA, Europe)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Special Edition (USA, Europe).gba" size 33554432 crc e9b7b8a4 sha1 5f17d2ec1a3ba1d605d486b6f6abcde6d82df767 ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Volume 1 (USA, Europe)" + description "Game Boy Advance Video - Cartoon Network Collection - Volume 1 (USA, Europe)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Volume 1 (USA, Europe).gba" size 33554432 crc 91f39447 sha1 3227d82e64024a5dc0e5b7f3fd768b0fec19e9b0 ) +) + +game ( + name "Game Boy Advance Video - Cartoon Network Collection - Volume 2 (USA, Europe)" + description "Game Boy Advance Video - Cartoon Network Collection - Volume 2 (USA, Europe)" + rom ( name "Game Boy Advance Video - Cartoon Network Collection - Volume 2 (USA, Europe).gba" size 33554432 crc 4bfaa8de sha1 692ffa1856780edd28b3aa55526ad06eeddc292e ) +) + +game ( + name "Game Boy Advance Video - Codename - Kids Next Door - Volume 1 (USA, Europe)" + description "Game Boy Advance Video - Codename - Kids Next Door - Volume 1 (USA, Europe)" + rom ( name "Game Boy Advance Video - Codename - Kids Next Door - Volume 1 (USA, Europe).gba" size 33554432 crc 4463f345 sha1 5e78808676213d6e5b55a78560fc47112f3008d4 ) +) + +game ( + name "Game Boy Advance Video - Disney Channel Collection - Volume 1 (USA)" + description "Game Boy Advance Video - Disney Channel Collection - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Disney Channel Collection - Volume 1 (USA).gba" size 33554432 crc 7cc985cb sha1 53069a5a8b564495ad800f0685b4d1970859b0f8 ) +) + +game ( + name "Game Boy Advance Video - Disney Channel Collection - Volume 2 (USA) (Rev 5)" + description "Game Boy Advance Video - Disney Channel Collection - Volume 2 (USA) (Rev 5)" + rom ( name "Game Boy Advance Video - Disney Channel Collection - Volume 2 (USA) (Rev 5).gba" size 33554432 crc da3b64f3 sha1 6bb825bd00a8daae329ea40cdbfd3db48547585e ) +) + +game ( + name "Game Boy Advance Video - Dora the Explorer - Volume 1 (USA)" + description "Game Boy Advance Video - Dora the Explorer - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Dora the Explorer - Volume 1 (USA).gba" size 33554432 crc dd6a7fcc sha1 67fe664bdadc7927ba888014ea923f11e3334b6c ) +) + +game ( + name "Game Boy Advance Video - Dragon Ball GT - Volume 1 (USA)" + description "Game Boy Advance Video - Dragon Ball GT - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Dragon Ball GT - Volume 1 (USA).gba" size 33554432 crc da559199 sha1 dc85cccc0cede3fc11d257995cd7d3cc64ca00e0 ) +) + +game ( + name "Game Boy Advance Video - Nicktoons - Volume 3 (USA)" + description "Game Boy Advance Video - Nicktoons - Volume 3 (USA)" + rom ( name "Game Boy Advance Video - Nicktoons - Volume 3 (USA).gba" size 33554432 crc 6fbf5ceb sha1 2732103fda15d8fb017f21023d2fda22ae7a548a ) +) + +game ( + name "Game Boy Advance Video - Nicktoons Collection - Volume 1 (USA)" + description "Game Boy Advance Video - Nicktoons Collection - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Nicktoons Collection - Volume 1 (USA).gba" size 33554432 crc 5d47676f sha1 b3bf6d95b548a82808a109cefaaf8b0c22ca66f2 ) +) + +game ( + name "Game Boy Advance Video - Nicktoons Collection - Volume 2 (USA)" + description "Game Boy Advance Video - Nicktoons Collection - Volume 2 (USA)" + rom ( name "Game Boy Advance Video - Nicktoons Collection - Volume 2 (USA).gba" size 33554432 crc 65deeeb6 sha1 03a767124f034b1eea51ab84ba6e80ec76f7f50c flags verified ) +) + +game ( + name "Game Boy Advance Video - Pokemon - Volume 1 (USA)" + description "Game Boy Advance Video - Pokemon - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Pokemon - Volume 1 (USA).gba" size 33554432 crc a59ef954 sha1 ad0164df397860b0967590ee46ca1f41d6cecdcd ) +) + +game ( + name "Game Boy Advance Video - Pokemon - Volume 2 (USA)" + description "Game Boy Advance Video - Pokemon - Volume 2 (USA)" + rom ( name "Game Boy Advance Video - Pokemon - Volume 2 (USA).gba" size 33554432 crc 0da1a383 sha1 e7b2e00d6a60e8c149cd07b0ee8d98bf2b4efd15 ) +) + +game ( + name "Game Boy Advance Video - Pokemon - Volume 3 (USA)" + description "Game Boy Advance Video - Pokemon - Volume 3 (USA)" + rom ( name "Game Boy Advance Video - Pokemon - Volume 3 (USA).gba" size 33554432 crc a36aa9c5 sha1 0f0020ef4278e1777baaf74b6787355a5cb57d50 ) +) + +game ( + name "Game Boy Advance Video - Pokemon - Volume 4 (USA)" + description "Game Boy Advance Video - Pokemon - Volume 4 (USA)" + rom ( name "Game Boy Advance Video - Pokemon - Volume 4 (USA).gba" size 33554432 crc be468496 sha1 fd79b821ff601e0091f19ab9c86b08f1c39ea2f3 ) +) + +game ( + name "Game Boy Advance Video - Shark Tale (USA) (Rev 5)" + description "Game Boy Advance Video - Shark Tale (USA) (Rev 5)" + rom ( name "Game Boy Advance Video - Shark Tale (USA) (Rev 5).gba" size 67108864 crc 01468820 sha1 6128a476edb10e6839ac5bd2697e83b9b7a9b234 ) +) + +game ( + name "Game Boy Advance Video - Shark Tale (USA) (Rev 6)" + description "Game Boy Advance Video - Shark Tale (USA) (Rev 6)" + rom ( name "Game Boy Advance Video - Shark Tale (USA) (Rev 6).gba" size 67108864 crc d2cf417a sha1 9bc5b60793b8a6de3b80eb2c213cd125e1fa468e flags verified ) +) + +game ( + name "Game Boy Advance Video - Shrek (USA) (Rev 5)" + description "Game Boy Advance Video - Shrek (USA) (Rev 5)" + rom ( name "Game Boy Advance Video - Shrek (USA) (Rev 5).gba" size 67108864 crc 690176e5 sha1 2dedea86ec289a0e31089299613d9f74cca03609 flags verified ) +) + +game ( + name "Game Boy Advance Video - Shrek (USA) (Rev 6)" + description "Game Boy Advance Video - Shrek (USA) (Rev 6)" + rom ( name "Game Boy Advance Video - Shrek (USA) (Rev 6).gba" size 67108864 crc 4010e9fa sha1 95d612057682b7b886441d387b167ba2493e49ef ) +) + +game ( + name "Game Boy Advance Video - Shrek + Shark Tale (USA) (Rev 5)" + description "Game Boy Advance Video - Shrek + Shark Tale (USA) (Rev 5)" + rom ( name "Game Boy Advance Video - Shrek + Shark Tale (USA) (Rev 5).gba" size 67108864 crc aadb3e3d sha1 f23390b7a62c605fbce6730addc29d381488e076 flags verified ) +) + +game ( + name "Game Boy Advance Video - Shrek 2 (USA) (Rev 6)" + description "Game Boy Advance Video - Shrek 2 (USA) (Rev 6)" + rom ( name "Game Boy Advance Video - Shrek 2 (USA) (Rev 6).gba" size 67108864 crc 925b6c02 sha1 3bcb4acc5da539bc1b91c9537bf7ffa081ded1d4 ) +) + +game ( + name "Game Boy Advance Video - Shrek 2 (USA) (Rev 5)" + description "Game Boy Advance Video - Shrek 2 (USA) (Rev 5)" + rom ( name "Game Boy Advance Video - Shrek 2 (USA) (Rev 5).gba" size 67108864 crc 0d353654 sha1 5cd627e205020297b25d707131883be5850515fe flags verified ) +) + +game ( + name "Game Boy Advance Video - Sonic X - Volume 1 (USA)" + description "Game Boy Advance Video - Sonic X - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Sonic X - Volume 1 (USA).gba" size 33554432 crc 363c3eb8 sha1 dc4c959a7740315d892633869f7fc6382aadbb0e ) +) + +game ( + name "Game Boy Advance Video - SpongeBob SquarePants - Volume 1 (USA) (Rev 1)" + description "Game Boy Advance Video - SpongeBob SquarePants - Volume 1 (USA) (Rev 1)" + rom ( name "Game Boy Advance Video - SpongeBob SquarePants - Volume 1 (USA) (Rev 1).gba" size 33554432 crc d47bf1d4 sha1 65f6b06c5397b9406960050025361550e0ff2e92 ) +) + +game ( + name "Game Boy Advance Video - SpongeBob SquarePants - Volume 2 (USA) (Rev 1)" + description "Game Boy Advance Video - SpongeBob SquarePants - Volume 2 (USA) (Rev 1)" + rom ( name "Game Boy Advance Video - SpongeBob SquarePants - Volume 2 (USA) (Rev 1).gba" size 33554432 crc 7074364a sha1 c4caa875f93657626bf73541ddd61eb5c8b4957e ) +) + +game ( + name "Game Boy Advance Video - SpongeBob SquarePants - Volume 3 (USA)" + description "Game Boy Advance Video - SpongeBob SquarePants - Volume 3 (USA)" + rom ( name "Game Boy Advance Video - SpongeBob SquarePants - Volume 3 (USA).gba" size 33554432 crc 9772ca45 sha1 fa11aeef21cdd18fcfea281990030acb65c7aa96 ) +) + +game ( + name "Game Boy Advance Video - Strawberry Shortcake - Volume 1 (USA)" + description "Game Boy Advance Video - Strawberry Shortcake - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Strawberry Shortcake - Volume 1 (USA).gba" size 33554432 crc ff7582ef sha1 f84cc8a33e3a75e42f4e8023a5cc851c92ea409a ) +) + +game ( + name "Game Boy Advance Video - Super Robot Monkey Team - Hyper Force Go! - Volume 1 (USA)" + description "Game Boy Advance Video - Super Robot Monkey Team - Hyper Force Go! - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - Super Robot Monkey Team - Hyper Force Go! - Volume 1 (USA).gba" size 33554432 crc d743a070 sha1 e3bce6ddf9437bded89fc662e992c1ab0aa1dbba ) +) + +game ( + name "Game Boy Advance Video - Teenage Mutant Ninja Turtles - Le Demenagement (France)" + description "Game Boy Advance Video - Teenage Mutant Ninja Turtles - Le Demenagement (France)" + rom ( name "Game Boy Advance Video - Teenage Mutant Ninja Turtles - Le Demenagement (France).gba" size 33554432 crc 1ee78166 sha1 1c7444a45c9bd15b1643c195832497881955acee ) +) + +game ( + name "Game Boy Advance Video - Teenage Mutant Ninja Turtles - Things Change (USA, Europe)" + description "Game Boy Advance Video - Teenage Mutant Ninja Turtles - Things Change (USA, Europe)" + rom ( name "Game Boy Advance Video - Teenage Mutant Ninja Turtles - Things Change (USA, Europe).gba" size 33554432 crc 046589c8 sha1 8b9665ce2cefd663f7722f38b64f9271f7c00daa ) +) + +game ( + name "Game Boy Advance Video - The Adventures of Jimmy Neutron Boy Genius - Volume 1 (USA)" + description "Game Boy Advance Video - The Adventures of Jimmy Neutron Boy Genius - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - The Adventures of Jimmy Neutron Boy Genius - Volume 1 (USA).gba" size 33554432 crc 0e556edf sha1 1414c55bd3d252fdc05c0a94085f12dddf86ea31 ) +) + +game ( + name "Game Boy Advance Video - The Fairly OddParents! - Volume 1 (USA)" + description "Game Boy Advance Video - The Fairly OddParents! - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - The Fairly OddParents! - Volume 1 (USA).gba" size 33554432 crc 7958df20 sha1 42e343e5048f99f05f7cde5aad6bfcc3d2410399 ) +) + +game ( + name "Game Boy Advance Video - The Fairly OddParents! - Volume 2 (USA) (Rev 1)" + description "Game Boy Advance Video - The Fairly OddParents! - Volume 2 (USA) (Rev 1)" + rom ( name "Game Boy Advance Video - The Fairly OddParents! - Volume 2 (USA) (Rev 1).gba" size 33554432 crc bbcbc6fd sha1 5b8a83410d8f9de12113e2974d65b5790aaf62fb ) +) + +game ( + name "Game Boy Advance Video - The Proud Family - Volume 1 (USA)" + description "Game Boy Advance Video - The Proud Family - Volume 1 (USA)" + rom ( name "Game Boy Advance Video - The Proud Family - Volume 1 (USA).gba" size 33554432 crc c6a91365 sha1 31a2cbb9b1b5adf7de399eecf2a9cec4f5412767 ) +) + +game ( + name "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey (France)" + description "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey (France)" + rom ( name "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey (France).gba" size 33554432 crc c9b6ccf1 sha1 8fb43e5018cf2d4b1a2aa2d1693862ce248ab6b0 ) +) + +game ( + name "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey (USA, Europe)" + description "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey (USA, Europe)" + rom ( name "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey (USA, Europe).gba" size 33554432 crc 8d631f4e sha1 6daf15bb61a10d1bbf94009886d6a76f9c937f8b flags verified ) +) + +clrmamepro ( + name "Nintendo - Game Boy" + description "Nintendo - Game Boy" + version 20240106-192522 + author "aci68, akubi, Arctic Circle System, Aringon, baldjared, Bent, BigFred, BitLooter, buckwheat, C. V. Reynolds, chillerecke, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, ElBarto, foxe, fuzzball, Gefflon, Hiccup, hking0036, InternalLoss, Jack, jimmsu, Just001Kim, kazumi213, leekindo, Lesserkuma, Madeline, NESBrew12, NGEfreak, nnssxx, norkmetnoil577, NovaAurora, omonim2007, Powerpuff, PPLToast, Psychofox11, rarenight, relax, RetroUprising, rpg2813, sCZther, SonGoku, Tauwasser, togemet2, UnlockerPT, xNo, xprism, xuom2" + homepage No-Intro + url "https://www.no-intro.org" + forcenodump required +) + +emulator ( + name "datafile" +) + +game ( + name "[BIOS] Maxstation Boot ROM (China) (En) (Unl)" + description "[BIOS] Maxstation Boot ROM (China) (En) (Unl)" + rom ( name "[BIOS] Maxstation Boot ROM (China) (En) (Unl).gb" size 256 crc 783e69c2 sha1 1776bd61b8db71fc4c4d4b5feab4a21b3c1fd95b ) ) game ( @@ -20788,6 +21612,12 @@ game ( rom ( name "[BIOS] Nintendo Game Boy Boot ROM (World) (Rev 1).gb" size 256 crc 59c8598e sha1 4ed31ec6b0b175bb109c0eb5fd3d193da823339f flags verified ) ) +game ( + name "[BIOS] Nintendo Game Boy Boot ROM (Japan) (En)" + description "[BIOS] Nintendo Game Boy Boot ROM (Japan) (En)" + rom ( name "[BIOS] Nintendo Game Boy Boot ROM (Japan) (En).gb" size 256 crc c2f5cc97 sha1 8bd501e31921e9601788316dbd3ce9833a97bcbc flags verified ) +) + game ( name "[BIOS] Nintendo Game Boy Pocket Boot ROM (World)" description "[BIOS] Nintendo Game Boy Pocket Boot ROM (World)" @@ -20795,33 +21625,15 @@ game ( ) game ( - name "10-Pin Bowling (USA)" - description "10-Pin Bowling (USA)" - rom ( name "10-Pin Bowling (USA).gb" size 131072 crc 9a024415 sha1 952d154dd2c6189ef4b786ae37bd7887c8ca9037 ) + name "10-Pin Bowling (USA) (Proto)" + description "10-Pin Bowling (USA) (Proto)" + rom ( name "10-Pin Bowling (USA) (Proto).gb" size 131072 crc 9a024415 sha1 952d154dd2c6189ef4b786ae37bd7887c8ca9037 ) ) game ( - name "1bit Game Collection (World) (Aftermarket) (Homebrew)" - description "1bit Game Collection (World) (Aftermarket) (Homebrew)" - rom ( name "1bit Game Collection (World) (Aftermarket) (Homebrew).gbc" size 131072 crc 7230319a sha1 8ab9b6d16e374172f9a88a3eded19f4888179143 flags verified ) -) - -game ( - name "2097 ROM Pack II (USA) (Test Program)" - description "2097 ROM Pack II (USA) (Test Program)" - rom ( name "2097 ROM Pack II (USA) (Test Program).gb" size 32768 crc 0a9ab6e7 sha1 68968d1b1fc84b2381159c0938675d2048c57ee2 ) -) - -game ( - name "2420 ROM Pack V (USA) (Test Program)" - description "2420 ROM Pack V (USA) (Test Program)" - rom ( name "2420 ROM Pack V (USA) (Test Program).gb" size 32768 crc 97561d80 sha1 a55a5fd97ca1be3fa129f744f81fc972e29418ac ) -) - -game ( - name "2440 ROM Pack (USA) (Test Program)" - description "2440 ROM Pack (USA) (Test Program)" - rom ( name "2440 ROM Pack (USA) (Test Program).gb" size 32768 crc 7a9359ea sha1 c15325e2e0ad2c8bd4323ef2390df28e578dcdb8 ) + name "14 Juillet (World) (Fr) (Aftermarket) (Unl)" + description "14 Juillet (World) (Fr) (Aftermarket) (Unl)" + rom ( name "14 Juillet (World) (Fr) (Aftermarket) (Unl).gb" size 1048576 crc 7b66bee4 sha1 02f387457a779cbd2f493e52743cd32c169c098e ) ) game ( @@ -20909,9 +21721,9 @@ game ( ) game ( - name "8-in-1 (Unknown) (Unl)" - description "8-in-1 (Unknown) (Unl)" - rom ( name "8-in-1 (Unknown) (Unl).gb" size 524288 crc fbc77225 sha1 f57efd4d5063cb87519fc3b574377cc9a2a841ee ) + name "8-in-1 (Taiwan) (En) (Unl)" + description "8-in-1 (Taiwan) (En) (Unl)" + rom ( name "8-in-1 (Taiwan) (En) (Unl).gb" size 524288 crc fbc77225 sha1 f57efd4d5063cb87519fc3b574377cc9a2a841ee ) ) game ( @@ -20926,6 +21738,12 @@ game ( rom ( name "Aa Harimanada (Japan).gb" size 131072 crc 5bffcc28 sha1 ff3565fcac22b44bf542732d1b0b20ba96a6c961 ) ) +game ( + name "Action Replay Pro (World)" + description "Action Replay Pro (World)" + rom ( name "Action Replay Pro (World).gb" size 16384 crc 2ea05daa sha1 e947b9264092168950ad1ce23bbe3d8ccfed765e ) +) + game ( name "Addams Family, The (Europe) (En,Fr,De)" description "Addams Family, The (Europe) (En,Fr,De)" @@ -20950,6 +21768,12 @@ game ( rom ( name "Addams Family, The - Pugsley's Scavenger Hunt (USA, Europe).gb" size 131072 crc 7e054a88 sha1 f9020e3d104cb5c5347e28f45ed9e24e6c0ebddd flags verified ) ) +game ( + name "Adulting! (World) (v2.0) (Aftermarket) (Unl)" + description "Adulting! (World) (v2.0) (Aftermarket) (Unl)" + rom ( name "Adulting! (World) (v2.0) (Aftermarket) (Unl).gb" size 524288 crc e56d1244 sha1 d107bd8bf32d0d94a988466885fe1a44aae32c9a flags verified ) +) + game ( name "Adventure Island (USA, Europe)" description "Adventure Island (USA, Europe)" @@ -21125,9 +21949,9 @@ game ( ) game ( - name "Alphamax (World) (Aftermarket) (Homebrew)" - description "Alphamax (World) (Aftermarket) (Homebrew)" - rom ( name "Alphamax (World) (Aftermarket) (Homebrew).gb" size 131072 crc 8b493b41 sha1 798dda34d04a06dcee32f44f8a4a045caf734927 ) + name "Alphamax (World) (Aftermarket) (Unl)" + description "Alphamax (World) (Aftermarket) (Unl)" + rom ( name "Alphamax (World) (Aftermarket) (Unl).gb" size 131072 crc 8b493b41 sha1 798dda34d04a06dcee32f44f8a4a045caf734927 ) ) game ( @@ -21220,12 +22044,6 @@ game ( rom ( name "Animaniacs (USA) (SGB Enhanced).gb" size 262144 crc 673c815d sha1 a0732f81e0c4f1bba592563bdc0eaae9d759ef28 flags verified ) ) -game ( - name "Another Adventure (World) (Aftermarket) (Homebrew)" - description "Another Adventure (World) (Aftermarket) (Homebrew)" - rom ( name "Another Adventure (World) (Aftermarket) (Homebrew).gb" size 1048576 crc dfcd02ef sha1 041473b2381dd9e11b3cbda5858f9841324327af ) -) - game ( name "Another Bible (Japan) (SGB Enhanced)" description "Another Bible (Japan) (SGB Enhanced)" @@ -21239,9 +22057,9 @@ game ( ) game ( - name "[MIA] Aprilia - DiTech Interface (Unknown) (Unl) [b]" - description "[MIA] Aprilia - DiTech Interface (Unknown) (Unl) [b]" - rom ( name "Aprilia - DiTech Interface (Unknown) (Unl) [b].gb" size 32768 crc 07d0f62c sha1 134625e507bc230efa236908034449fb1afcfdfc flags baddump ) + name "Aprilia - DiTech Interface (Unknown) (Unl) [b]" + description "Aprilia - DiTech Interface (Unknown) (Unl) [b]" + rom ( name "Aprilia - DiTech Interface (Unknown) (Unl) [b].gb" size 262144 crc 2e47d2d3 sha1 a921679b79191991eb75de3b6b21443f322a3699 flags baddump ) ) game ( @@ -21299,27 +22117,27 @@ game ( ) game ( - name "Art School Pocket (World) (Aftermarket) (Homebrew)" - description "Art School Pocket (World) (Aftermarket) (Homebrew)" - rom ( name "Art School Pocket (World) (Aftermarket) (Homebrew).gb" size 1048576 crc b4eab528 sha1 c482cfc6ec40b1f33c4ba48ecdc45fef4730b653 ) + name "Art School Pocket (World) (En) (Aftermarket) (Unl)" + description "Art School Pocket (World) (En) (Aftermarket) (Unl)" + rom ( name "Art School Pocket (World) (En) (Aftermarket) (Unl).gb" size 1048576 crc b4eab528 sha1 c482cfc6ec40b1f33c4ba48ecdc45fef4730b653 ) ) game ( - name "Art School Pocket (Spain) (Aftermarket) (Homebrew)" - description "Art School Pocket (Spain) (Aftermarket) (Homebrew)" - rom ( name "Art School Pocket (Spain) (Aftermarket) (Homebrew).gb" size 1048576 crc 240067df sha1 c8a75895c87b11f9493f629c19c54d0c607505bd ) + name "Art School Pocket (World) (Es) (Aftermarket) (Unl)" + description "Art School Pocket (World) (Es) (Aftermarket) (Unl)" + rom ( name "Art School Pocket (World) (Es) (Aftermarket) (Unl).gb" size 1048576 crc 240067df sha1 c8a75895c87b11f9493f629c19c54d0c607505bd ) ) game ( - name "Art School Pocket (France) (Aftermarket) (Homebrew)" - description "Art School Pocket (France) (Aftermarket) (Homebrew)" - rom ( name "Art School Pocket (France) (Aftermarket) (Homebrew).gb" size 1048576 crc 49a5b74d sha1 73ecffaee185eb2caf1db385d04b863676c777fb ) + name "Art School Pocket (World) (Fr) (Aftermarket) (Unl)" + description "Art School Pocket (World) (Fr) (Aftermarket) (Unl)" + rom ( name "Art School Pocket (World) (Fr) (Aftermarket) (Unl).gb" size 1048576 crc 49a5b74d sha1 73ecffaee185eb2caf1db385d04b863676c777fb ) ) game ( - name "Art School Pocket (Germany) (Aftermarket) (Homebrew)" - description "Art School Pocket (Germany) (Aftermarket) (Homebrew)" - rom ( name "Art School Pocket (Germany) (Aftermarket) (Homebrew).gb" size 1048576 crc 82b73e5b sha1 7772e2b9d5e722e54d19fc6283ccb1fa5d19b641 ) + name "Art School Pocket (World) (De) (Aftermarket) (Unl)" + description "Art School Pocket (World) (De) (Aftermarket) (Unl)" + rom ( name "Art School Pocket (World) (De) (Aftermarket) (Unl).gb" size 1048576 crc 82b73e5b sha1 7772e2b9d5e722e54d19fc6283ccb1fa5d19b641 ) ) game ( @@ -21382,6 +22200,12 @@ game ( rom ( name "Asteroids (USA, Europe) (Beta).gb" size 32768 crc eb31e472 sha1 28f4e2a076bfe5f7a77f695332705ea0085fccfb ) ) +game ( + name "Asteroids Chasers (World) (Aftermarket) (Unl)" + description "Asteroids Chasers (World) (Aftermarket) (Unl)" + rom ( name "Asteroids Chasers (World) (Aftermarket) (Unl).gb" size 131072 crc 58d8b1b8 sha1 f93a4e6788eaf0231a6ca269cca297f0d45ec830 flags verified ) +) + game ( name "Astro Rabby (Japan)" description "Astro Rabby (Japan)" @@ -21389,15 +22213,15 @@ game ( ) game ( - name "Astro-Jump (World) (Aftermarket) (Homebrew)" - description "Astro-Jump (World) (Aftermarket) (Homebrew)" - rom ( name "Astro-Jump (World) (Aftermarket) (Homebrew).gb" size 262144 crc c35a3b39 sha1 1bcb4be684626ce061aad105701548fa3a77e254 ) + name "Astro-Jump (World) (Aftermarket) (Unl)" + description "Astro-Jump (World) (Aftermarket) (Unl)" + rom ( name "Astro-Jump (World) (Aftermarket) (Unl).gb" size 262144 crc c35a3b39 sha1 1bcb4be684626ce061aad105701548fa3a77e254 ) ) game ( - name "Astro-Jump - The Sequel (World) (Aftermarket) (Homebrew)" - description "Astro-Jump - The Sequel (World) (Aftermarket) (Homebrew)" - rom ( name "Astro-Jump - The Sequel (World) (Aftermarket) (Homebrew).gb" size 131072 crc e6a96130 sha1 2cd0ef086c4b89497d9497a17d871a6568a9e2d3 ) + name "Athletic World (World) (Demo) (SGB Enhanced) (Aftermarket) (Unl)" + description "Athletic World (World) (Demo) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Athletic World (World) (Demo) (SGB Enhanced) (Aftermarket) (Unl).gb" size 131072 crc afc128f2 sha1 956be9371990b18e351f2e10848b2ea8bb70c2b7 ) ) game ( @@ -21419,15 +22243,9 @@ game ( ) game ( - name "Auto Zone (World) (Aftermarket) (Homebrew)" - description "Auto Zone (World) (Aftermarket) (Homebrew)" - rom ( name "Auto Zone (World) (Aftermarket) (Homebrew).gb" size 524288 crc cee73c14 sha1 3070ec215014633dac5dbbb487aade2e2993c049 ) -) - -game ( - name "Autumn With You, An (World) (Aftermarket) (Homebrew)" - description "Autumn With You, An (World) (Aftermarket) (Homebrew)" - rom ( name "Autumn With You, An (World) (Aftermarket) (Homebrew).gb" size 262144 crc eac459fa sha1 68a5520be76c52a4936ad1756ea274667f2ac0e3 ) + name "Auto Zone (World) (Aftermarket) (Unl)" + description "Auto Zone (World) (Aftermarket) (Unl)" + rom ( name "Auto Zone (World) (Aftermarket) (Unl).gb" size 524288 crc cee73c14 sha1 3070ec215014633dac5dbbb487aade2e2993c049 ) ) game ( @@ -21559,7 +22377,7 @@ game ( game ( name "Bases Loaded (USA)" description "Bases Loaded (USA)" - rom ( name "Bases Loaded (USA).gb" size 131072 crc d37a2fdf sha1 5220db2e87622648caeacdfb8d4f564c9bf479fc ) + rom ( name "Bases Loaded (USA).gb" size 131072 crc d37a2fdf sha1 5220db2e87622648caeacdfb8d4f564c9bf479fc flags verified ) ) game ( @@ -21790,12 +22608,24 @@ game ( rom ( name "Bill & Ted's Excellent Game Boy Adventure - A Bogus Journey! (USA, Europe).gb" size 131072 crc 5e8f656a sha1 e19a7e5a5bd8fde0f31773c22dbebc9b4cf3824e flags verified ) ) +game ( + name "Bill & Ted's Excellent Portable Adventure - A Bogus Journey! (World) (Retro Collection)" + description "Bill & Ted's Excellent Portable Adventure - A Bogus Journey! (World) (Retro Collection)" + rom ( name "Bill & Ted's Excellent Portable Adventure - A Bogus Journey! (World) (Retro Collection).gb" size 131072 crc 7b5e19ca sha1 c6e606cb5e17f7530a529387ad2fb703a94b205a flags verified ) +) + game ( name "Bill Elliott's NASCAR Fast Tracks (USA)" description "Bill Elliott's NASCAR Fast Tracks (USA)" rom ( name "Bill Elliott's NASCAR Fast Tracks (USA).gb" size 131072 crc 71cf43ce sha1 ebc2ca8b4503f0b05e00749d693462a54f2f95eb ) ) +game ( + name "Binding of Isaac, The - Game Boy Edition (World) (Aftermarket) (Unl)" + description "Binding of Isaac, The - Game Boy Edition (World) (Aftermarket) (Unl)" + rom ( name "Binding of Isaac, The - Game Boy Edition (World) (Aftermarket) (Unl).gb" size 32768 crc bf922249 sha1 187782720d4f7c0986a0d916b0c7efa2c488612e ) +) + game ( name "Bionic Battler (USA)" description "Bionic Battler (USA)" @@ -21820,6 +22650,12 @@ game ( rom ( name "Bionic Commando (USA).gb" size 262144 crc 41dbb5fb sha1 e0ef47568a017ccdd3dbe0db5d7654822b4e5ce1 ) ) +game ( + name "Birdie Bartender (World) (Aftermarket) (Unl)" + description "Birdie Bartender (World) (Aftermarket) (Unl)" + rom ( name "Birdie Bartender (World) (Aftermarket) (Unl).gb" size 262144 crc 0bf2a1c8 sha1 aa1325fc7160b84745b076de9b976a1b368da50e ) +) + game ( name "Bishoujo Senshi Sailor Moon (Japan)" description "Bishoujo Senshi Sailor Moon (Japan)" @@ -21839,15 +22675,9 @@ game ( ) game ( - name "Black Castle GB (World) (Aftermarket) (Homebrew)" - description "Black Castle GB (World) (Aftermarket) (Homebrew)" - rom ( name "Black Castle GB (World) (Aftermarket) (Homebrew).gb" size 65536 crc 10f577c7 sha1 45d979be572bb820835d2ecd4e990cd1eadbf5a6 ) -) - -game ( - name "Black Tape (World) (Aftermarket) (Homebrew)" - description "Black Tape (World) (Aftermarket) (Homebrew)" - rom ( name "Black Tape (World) (Aftermarket) (Homebrew).gb" size 524288 crc 45c5f990 sha1 ec8c467e955d69b2084805f11a954e0d90855461 ) + name "Black Castle (World) (Aftermarket) (Unl)" + description "Black Castle (World) (Aftermarket) (Unl)" + rom ( name "Black Castle (World) (Aftermarket) (Unl).gb" size 65536 crc 10f577c7 sha1 45d979be572bb820835d2ecd4e990cd1eadbf5a6 ) ) game ( @@ -21887,9 +22717,9 @@ game ( ) game ( - name "Blitz Bomber (World) (Aftermarket) (Homebrew)" - description "Blitz Bomber (World) (Aftermarket) (Homebrew)" - rom ( name "Blitz Bomber (World) (Aftermarket) (Homebrew).gb" size 262144 crc 5e9956de sha1 b72cbc6bfa6ceef940f49c9c82024071c6f82b90 ) + name "Blitz Bomber (World) (Aftermarket) (Unl)" + description "Blitz Bomber (World) (Aftermarket) (Unl)" + rom ( name "Blitz Bomber (World) (Aftermarket) (Unl).gb" size 262144 crc 5e9956de sha1 b72cbc6bfa6ceef940f49c9c82024071c6f82b90 ) ) game ( @@ -21899,9 +22729,9 @@ game ( ) game ( - name "Blockade (World) (Aftermarket) (Homebrew)" - description "Blockade (World) (Aftermarket) (Homebrew)" - rom ( name "Blockade (World) (Aftermarket) (Homebrew).gb" size 262144 crc b8cfab16 sha1 9e753048a0eb036ac17c08f5a64d860abd1aaaf5 ) + name "Blockade (World) (Aftermarket) (Unl)" + description "Blockade (World) (Aftermarket) (Unl)" + rom ( name "Blockade (World) (Aftermarket) (Unl).gb" size 262144 crc b8cfab16 sha1 9e753048a0eb036ac17c08f5a64d860abd1aaaf5 ) ) game ( @@ -21910,6 +22740,12 @@ game ( rom ( name "Blodia (Japan).gb" size 65536 crc 51ff6e53 sha1 a3927543ca471f479ba7aae7295788434672464e ) ) +game ( + name "Blues Brothers (USA, Europe) (Beta)" + description "Blues Brothers (USA, Europe) (Beta)" + rom ( name "Blues Brothers (USA, Europe) (Beta).gb" size 131072 crc 1f90d12a sha1 f7139bb55c3cc7bae672ade9022fb548b72f6f2f ) +) + game ( name "Blues Brothers, The (USA, Europe)" description "Blues Brothers, The (USA, Europe)" @@ -21925,7 +22761,7 @@ game ( game ( name "Bo Jackson - Two Games in One (USA)" description "Bo Jackson - Two Games in One (USA)" - rom ( name "Bo Jackson - Two Games in One (USA).gb" size 131072 crc 7edb78ab sha1 cb360f44a398ff5cd3818b0e244ffdf7019d85c7 ) + rom ( name "Bo Jackson - Two Games in One (USA).gb" size 131072 crc 7edb78ab sha1 cb360f44a398ff5cd3818b0e244ffdf7019d85c7 flags verified ) ) game ( @@ -21946,18 +22782,6 @@ game ( rom ( name "Boggle Plus (USA).gb" size 131072 crc 70c8c799 sha1 d6cf512f7301ccdc2d802f34fbbde2d0ba2cf3cd ) ) -game ( - name "BOING! (World) (Aftermarket) (Homebrew)" - description "BOING! (World) (Aftermarket) (Homebrew)" - rom ( name "BOING! (World) (Aftermarket) (Homebrew).gb" size 2097152 crc 91961796 sha1 09fde4065941784bab4cf8f624a0398049ed4add ) -) - -game ( - name "Bokujou Monogatari GB (Japan) (SGB Enhanced) (NP)" - description "Bokujou Monogatari GB (Japan) (SGB Enhanced) (NP)" - rom ( name "Bokujou Monogatari GB (Japan) (SGB Enhanced) (NP).gb" size 524288 crc 0424df85 sha1 551df2021d0e433e7f07cf881c7b1d534f54f6ad ) -) - game ( name "Bokujou Monogatari GB (Japan) (SGB Enhanced)" description "Bokujou Monogatari GB (Japan) (SGB Enhanced)" @@ -21971,9 +22795,9 @@ game ( ) game ( - name "Bomb Jack (Europe)" - description "Bomb Jack (Europe)" - rom ( name "Bomb Jack (Europe).gb" size 32768 crc 9bd8815e sha1 a2b2799e867777a5a19155ed1f2245630fc03560 ) + name "Bokujou Monogatari GB (Japan) (SGB Enhanced) (NP)" + description "Bokujou Monogatari GB (Japan) (SGB Enhanced) (NP)" + rom ( name "Bokujou Monogatari GB (Japan) (SGB Enhanced) (NP).gb" size 524288 crc 0424df85 sha1 551df2021d0e433e7f07cf881c7b1d534f54f6ad ) ) game ( @@ -21988,6 +22812,12 @@ game ( rom ( name "Bomb Jack (Europe) (Beta 2).gb" size 32768 crc 7ca8e543 sha1 6fc3794149f5e75ad82b4a7d47ad5497e1ee4e6a ) ) +game ( + name "Bomb Jack (Europe)" + description "Bomb Jack (Europe)" + rom ( name "Bomb Jack (Europe).gb" size 32768 crc 9bd8815e sha1 a2b2799e867777a5a19155ed1f2245630fc03560 ) +) + game ( name "Bomber Boy (Japan)" description "Bomber Boy (Japan)" @@ -22015,7 +22845,7 @@ game ( game ( name "Bomberman GB (USA, Europe) (SGB Enhanced)" description "Bomberman GB (USA, Europe) (SGB Enhanced)" - rom ( name "Bomberman GB (USA, Europe) (SGB Enhanced).gb" size 262144 crc f372d175 sha1 f7058f31ddaec63f3b9c45ee9caf3c8e2cae1ca8 ) + rom ( name "Bomberman GB (USA, Europe) (SGB Enhanced).gb" size 262144 crc f372d175 sha1 f7058f31ddaec63f3b9c45ee9caf3c8e2cae1ca8 flags verified ) ) game ( @@ -22061,9 +22891,15 @@ game ( ) game ( - name "Borbo's Quest (World) (Aftermarket) (Homebrew)" - description "Borbo's Quest (World) (Aftermarket) (Homebrew)" - rom ( name "Borbo's Quest (World) (Aftermarket) (Homebrew).gb" size 1048576 crc e92ce3d4 sha1 1ddf864188dfd741ccda0b0715e75e162d212605 ) + name "Bork Paw Kisses (World) (Aftermarket) (Unl)" + description "Bork Paw Kisses (World) (Aftermarket) (Unl)" + rom ( name "Bork Paw Kisses (World) (Aftermarket) (Unl).gb" size 262144 crc c29f0d35 sha1 8f1efe6982d2b4ebc1fbeb3ade68dd9b9aabb7a6 ) +) + +game ( + name "Borruga - Neo Pinball (World) (Aftermarket) (Unl)" + description "Borruga - Neo Pinball (World) (Aftermarket) (Unl)" + rom ( name "Borruga - Neo Pinball (World) (Aftermarket) (Unl).gb" size 32768 crc 2bb55ca5 sha1 269f12091d5ab87362a2cb2cf5484f14bfcbd537 flags verified ) ) game ( @@ -22085,9 +22921,21 @@ game ( ) game ( - name "Bounce (World) (v1.1) (Homebrew)" - description "Bounce (World) (v1.1) (Homebrew)" - rom ( name "Bounce (World) (v1.1) (Homebrew).gb" size 32768 crc 827f2bd5 sha1 e9abf64de3faeb48151003ac8bb77dea61e838b5 ) + name "Bounce (World) (v1.1) (Aftermarket) (Unl)" + description "Bounce (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Bounce (World) (v1.1) (Aftermarket) (Unl).gb" size 32768 crc 827f2bd5 sha1 e9abf64de3faeb48151003ac8bb77dea61e838b5 ) +) + +game ( + name "Bouncing Ball, The (World) (Aftermarket)" + description "Bouncing Ball, The (World) (Aftermarket)" + rom ( name "Bouncing Ball, The (World) (Aftermarket).gb" size 65536 crc 42ddf53e sha1 5d331f2e66d7d3f4b4b0fcbaf6ab4b1a0147db3e ) +) + +game ( + name "Bourgogne Game Show 2022 (World) (Aftermarket) (Unl)" + description "Bourgogne Game Show 2022 (World) (Aftermarket) (Unl)" + rom ( name "Bourgogne Game Show 2022 (World) (Aftermarket) (Unl).gb" size 262144 crc 98222a4a sha1 0bdb8ad04469a329c8cee2fb0c55da35f7752042 ) ) game ( @@ -22210,6 +23058,12 @@ game ( rom ( name "Bubsy II (USA).gb" size 262144 crc 600a6ad5 sha1 1ac9bf5043caf428994bca3e80158ca697e94c58 ) ) +game ( + name "Bug Bites! (World) (Aftermarket) (Unl)" + description "Bug Bites! (World) (Aftermarket) (Unl)" + rom ( name "Bug Bites! (World) (Aftermarket) (Unl).gb" size 262144 crc bb473d7a sha1 8d601612ac262e4548d8b8f6ac19a04cb92ecfb7 ) +) + game ( name "Bugs Bunny Collection (Japan) (SGB Enhanced)" description "Bugs Bunny Collection (Japan) (SGB Enhanced)" @@ -22235,21 +23089,21 @@ game ( ) game ( - name "Bung Greetings Demo (World) (Demo) (Homebrew)" - description "Bung Greetings Demo (World) (Demo) (Homebrew)" - rom ( name "Bung Greetings Demo (World) (Demo) (Homebrew).gb" size 65536 crc 1ae05af4 sha1 bb01f845d330377749aeb6df1f7bea0eff78bb89 ) + name "Bung Greetings Demo (World) (Demo) (Unl)" + description "Bung Greetings Demo (World) (Demo) (Unl)" + rom ( name "Bung Greetings Demo (World) (Demo) (Unl).gb" size 65536 crc 1ae05af4 sha1 bb01f845d330377749aeb6df1f7bea0eff78bb89 ) ) game ( - name "Bung New Year's Greetings Demo (World) (Demo) (Homebrew)" - description "Bung New Year's Greetings Demo (World) (Demo) (Homebrew)" - rom ( name "Bung New Year's Greetings Demo (World) (Demo) (Homebrew).gb" size 65536 crc 493d4a1e sha1 737402fe70924f893fc212393eeb7f46f225745a ) + name "Bung New Year's Greetings Demo (World) (Demo) (Unl)" + description "Bung New Year's Greetings Demo (World) (Demo) (Unl)" + rom ( name "Bung New Year's Greetings Demo (World) (Demo) (Unl).gb" size 65536 crc 493d4a1e sha1 737402fe70924f893fc212393eeb7f46f225745a ) ) game ( - name "Bung's Math Test (World) (Homebrew)" - description "Bung's Math Test (World) (Homebrew)" - rom ( name "Bung's Math Test (World) (Homebrew).gb" size 32768 crc ebeda9d2 sha1 68581c24793e8ea63f3273efa7bc098309d77d1a ) + name "Bung's Math Test (World) (Unl)" + description "Bung's Math Test (World) (Unl)" + rom ( name "Bung's Math Test (World) (Unl).gb" size 32768 crc ebeda9d2 sha1 68581c24793e8ea63f3273efa7bc098309d77d1a ) ) game ( @@ -22295,9 +23149,9 @@ game ( ) game ( - name "Busty Bunny the Bounty Babe (World) (v1.02) (Aftermarket) (Homebrew)" - description "Busty Bunny the Bounty Babe (World) (v1.02) (Aftermarket) (Homebrew)" - rom ( name "Busty Bunny the Bounty Babe (World) (v1.02) (Aftermarket) (Homebrew).gb" size 1048576 crc d0ed199c sha1 a1cbaacdf32cb8fb9a9c59fcb624c729e0ca17bf ) + name "Busty Bunny the Bounty Babe (World) (v1.02) (Aftermarket) (Unl)" + description "Busty Bunny the Bounty Babe (World) (v1.02) (Aftermarket) (Unl)" + rom ( name "Busty Bunny the Bounty Babe (World) (v1.02) (Aftermarket) (Unl).gb" size 1048576 crc d0ed199c sha1 a1cbaacdf32cb8fb9a9c59fcb624c729e0ca17bf ) ) game ( @@ -22327,7 +23181,7 @@ game ( game ( name "Caesars Palace (USA) (Rev 1)" description "Caesars Palace (USA) (Rev 1)" - rom ( name "Caesars Palace (USA) (Rev 1).gb" size 131072 crc 87a9d605 sha1 126e9ef9e975bbbc6303d5d62a379d4dbd404cf0 ) + rom ( name "Caesars Palace (USA) (Rev 1).gb" size 131072 crc 87a9d605 sha1 126e9ef9e975bbbc6303d5d62a379d4dbd404cf0 flags verified ) ) game ( @@ -22432,6 +23286,12 @@ game ( rom ( name "Castle Quest (Europe) (Beta).gb" size 131072 crc 8a5636ea sha1 356c8510b0647e56a558aba9d5dc4cc9d3ccd94c ) ) +game ( + name "Castledark (World) (v2.0) (Demo) (Aftermarket) (Unl)" + description "Castledark (World) (v2.0) (Demo) (Aftermarket) (Unl)" + rom ( name "Castledark (World) (v2.0) (Demo) (Aftermarket) (Unl).gb" size 524288 crc 3c492b31 sha1 0861af0039dab4b4f5bce747c6fcd586eced401a ) +) + game ( name "Castlevania - The Adventure (USA) (Castlevania Anniversary Collection)" description "Castlevania - The Adventure (USA) (Castlevania Anniversary Collection)" @@ -22480,6 +23340,12 @@ game ( rom ( name "Catrap (USA) (Beta).gb" size 32768 crc ca3bc888 sha1 928b9b3cb2ed5e6d6fc754679b3c994f7ed803c3 ) ) +game ( + name "Cave Fighter (World) (Aftermarket) (Unl)" + description "Cave Fighter (World) (Aftermarket) (Unl)" + rom ( name "Cave Fighter (World) (Aftermarket) (Unl).gb" size 262144 crc e8f91f6a sha1 290048717d0a8cabb3cc591161339550eb53c161 ) +) + game ( name "Cave Noire (Japan)" description "Cave Noire (Japan)" @@ -22529,9 +23395,15 @@ game ( ) game ( - name "Cherry Rescue! (World) (Aftermarket) (Homebrew)" - description "Cherry Rescue! (World) (Aftermarket) (Homebrew)" - rom ( name "Cherry Rescue! (World) (Aftermarket) (Homebrew).gb" size 524288 crc ba65812a sha1 740dba1827c730cc5d8bf67495bcede3a5352643 ) + name "Cheesy Town (World) (En,Ja) (Aftermarket) (Unl)" + description "Cheesy Town (World) (En,Ja) (Aftermarket) (Unl)" + rom ( name "Cheesy Town (World) (En,Ja) (Aftermarket) (Unl).gb" size 262144 crc 3e20c1a8 sha1 f76645a2830fcc733b7392a52112df628f0b7a4a ) +) + +game ( + name "Cherry Rescue! (World) (Aftermarket) (Unl)" + description "Cherry Rescue! (World) (Aftermarket) (Unl)" + rom ( name "Cherry Rescue! (World) (Aftermarket) (Unl).gb" size 524288 crc ba65812a sha1 740dba1827c730cc5d8bf67495bcede3a5352643 ) ) game ( @@ -22655,9 +23527,9 @@ game ( ) game ( - name "Christmas Carols (World) (Aftermarket) (Homebrew)" - description "Christmas Carols (World) (Aftermarket) (Homebrew)" - rom ( name "Christmas Carols (World) (Aftermarket) (Homebrew).gb" size 262144 crc a00bb310 sha1 e19b0a698d8194467d57c00664f00f9898ee5368 ) + name "Christmas Carols (World) (Aftermarket) (Unl)" + description "Christmas Carols (World) (Aftermarket) (Unl)" + rom ( name "Christmas Carols (World) (Aftermarket) (Unl).gb" size 262144 crc a00bb310 sha1 e19b0a698d8194467d57c00664f00f9898ee5368 ) ) game ( @@ -22667,27 +23539,27 @@ game ( ) game ( - name "Ciao Nonna (World) (v1.1) (Aftermarket) (Homebrew)" - description "Ciao Nonna (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Ciao Nonna (World) (v1.1) (Aftermarket) (Homebrew).gb" size 1048576 crc 4cd61bbf sha1 4bcae0e12b4d999099ce7ceb6d44c5ac45eeb292 ) + name "Ciao Nonna (World) (v1.1) (Aftermarket) (Unl)" + description "Ciao Nonna (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Ciao Nonna (World) (v1.1) (Aftermarket) (Unl).gb" size 1048576 crc 2165f2e4 sha1 f8e5020298183c3f47836da3890b6bb398e2ecab ) ) game ( - name "Ciao Nonna (World) (v2.0) (Aftermarket) (Homebrew)" - description "Ciao Nonna (World) (v2.0) (Aftermarket) (Homebrew)" - rom ( name "Ciao Nonna (World) (v2.0) (Aftermarket) (Homebrew).gb" size 1048576 crc 85f7d6e3 sha1 468b4902440ba87fbb7c7dbf89b094ec5e24d123 ) + name "Ciao Nonna (World) (v2.0) (Aftermarket) (Unl)" + description "Ciao Nonna (World) (v2.0) (Aftermarket) (Unl)" + rom ( name "Ciao Nonna (World) (v2.0) (Aftermarket) (Unl).gb" size 1048576 crc 6afee818 sha1 602709c8655febb42899881a8ef598fb4b3da0c9 ) ) game ( - name "Ciao Nonna (World) (v2.1) (Aftermarket) (Homebrew)" - description "Ciao Nonna (World) (v2.1) (Aftermarket) (Homebrew)" - rom ( name "Ciao Nonna (World) (v2.1) (Aftermarket) (Homebrew).gb" size 1048576 crc 225ce296 sha1 45aebfe4e7f5382a4b31c3db270b75d2c458d1b2 ) + name "Ciao Nonna (World) (v2.1) (Aftermarket) (Unl)" + description "Ciao Nonna (World) (v2.1) (Aftermarket) (Unl)" + rom ( name "Ciao Nonna (World) (v2.1) (Aftermarket) (Unl).gb" size 1048576 crc 225ce296 sha1 45aebfe4e7f5382a4b31c3db270b75d2c458d1b2 ) ) game ( - name "Ciao Nonna (World) (v1.0) (Aftermarket) (Homebrew)" - description "Ciao Nonna (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Ciao Nonna (World) (v1.0) (Aftermarket) (Homebrew).gb" size 1048576 crc dd7576d6 sha1 0556eb6160fdca6e7959bba1a619b8e34d974375 ) + name "Ciao Nonna (World) (Aftermarket) (Unl)" + description "Ciao Nonna (World) (Aftermarket) (Unl)" + rom ( name "Ciao Nonna (World) (Aftermarket) (Unl).gb" size 1048576 crc dd7576d6 sha1 0556eb6160fdca6e7959bba1a619b8e34d974375 ) ) game ( @@ -22696,12 +23568,6 @@ game ( rom ( name "Cliffhanger (USA, Europe).gb" size 131072 crc aa133439 sha1 c74f85035842f8a2d9560066d7065ff86d9107e2 flags verified ) ) -game ( - name "Clockmaker's Tale, A (World) (Aftermarket) (Homebrew)" - description "Clockmaker's Tale, A (World) (Aftermarket) (Homebrew)" - rom ( name "Clockmaker's Tale, A (World) (Aftermarket) (Homebrew).gb" size 1048576 crc c4b00adb sha1 07e4254c7f74b9d4caa6a1231558b2430dff163a ) -) - game ( name "Collection Pocket (Japan) (SGB Enhanced)" description "Collection Pocket (Japan) (SGB Enhanced)" @@ -22715,9 +23581,9 @@ game ( ) game ( - name "Commando (World) (Aftermarket) (Homebrew)" - description "Commando (World) (Aftermarket) (Homebrew)" - rom ( name "Commando (World) (Aftermarket) (Homebrew).gb" size 262144 crc 48173941 sha1 c861858e9f2cf7470e739c26ae9f17d3834ce464 ) + name "Commando (World) (Aftermarket) (Unl)" + description "Commando (World) (Aftermarket) (Unl)" + rom ( name "Commando (World) (Aftermarket) (Unl).gb" size 262144 crc 48173941 sha1 c861858e9f2cf7470e739c26ae9f17d3834ce464 ) ) game ( @@ -22744,12 +23610,6 @@ game ( rom ( name "Contra Spirits (Japan) (SGB Enhanced).gb" size 131072 crc 7fc22df5 sha1 72213c5d8af05cad5f17a42566f7383066612eee ) ) -game ( - name "Cookie's Bakery (World) (v1.0.3) (Aftermarket) (Homebrew)" - description "Cookie's Bakery (World) (v1.0.3) (Aftermarket) (Homebrew)" - rom ( name "Cookie's Bakery (World) (v1.0.3) (Aftermarket) (Homebrew).gb" size 524288 crc c53ace00 sha1 02fdc52bc934b80aa41520d92cf0340753d8f668 ) -) - game ( name "Cool Ball (USA)" description "Cool Ball (USA)" @@ -22787,15 +23647,9 @@ game ( ) game ( - name "Coria and the Sunken City (Unknown) (Demo)" - description "Coria and the Sunken City (Unknown) (Demo)" - rom ( name "Coria and the Sunken City (Unknown) (Demo).gb" size 131072 crc fe1bdae6 sha1 00d86bbdbc228ff3ea0684984a261cadbed5fb0a ) -) - -game ( - name "Cosmic Courier - Trapped in Limbo (World) (Aftermarket) (Homebrew)" - description "Cosmic Courier - Trapped in Limbo (World) (Aftermarket) (Homebrew)" - rom ( name "Cosmic Courier - Trapped in Limbo (World) (Aftermarket) (Homebrew).gb" size 262144 crc fd304687 sha1 7df11ec2946099d49dd62928118b6d76703dc57c ) + name "Cosmic Courier - Trapped in Limbo (World) (Aftermarket) (Unl)" + description "Cosmic Courier - Trapped in Limbo (World) (Aftermarket) (Unl)" + rom ( name "Cosmic Courier - Trapped in Limbo (World) (Aftermarket) (Unl).gb" size 262144 crc fd304687 sha1 7df11ec2946099d49dd62928118b6d76703dc57c ) ) game ( @@ -22823,9 +23677,15 @@ game ( ) game ( - name "coucou (World) (Aftermarket) (Homebrew)" - description "coucou (World) (Aftermarket) (Homebrew)" - rom ( name "coucou (World) (Aftermarket) (Homebrew).gb" size 32768 crc e6aabd72 sha1 5283268e3640e2924d00aea3b12b2d3930bef43c ) + name "Coucou (World) (Aftermarket) (Unl)" + description "Coucou (World) (Aftermarket) (Unl)" + rom ( name "Coucou (World) (Aftermarket) (Unl).gb" size 32768 crc e6aabd72 sha1 5283268e3640e2924d00aea3b12b2d3930bef43c ) +) + +game ( + name "Counting Sheep (World) (Aftermarket) (Unl)" + description "Counting Sheep (World) (Aftermarket) (Unl)" + rom ( name "Counting Sheep (World) (Aftermarket) (Unl).GB" size 65536 crc 6e97c837 sha1 e7e251ad86fa00803837cf871de62d3f100c83ce ) ) game ( @@ -22877,9 +23737,9 @@ game ( ) game ( - name "Cuthbert in the Cooler (World) (Aftermarket) (Homebrew)" - description "Cuthbert in the Cooler (World) (Aftermarket) (Homebrew)" - rom ( name "Cuthbert in the Cooler (World) (Aftermarket) (Homebrew).gb" size 262144 crc 10838580 sha1 c740bc995adf2bb638bb125a36edc416558fd4c6 ) + name "Cuthbert in the Cooler (World) (Aftermarket) (Unl)" + description "Cuthbert in the Cooler (World) (Aftermarket) (Unl)" + rom ( name "Cuthbert in the Cooler (World) (Aftermarket) (Unl).gb" size 262144 crc 10838580 sha1 c740bc995adf2bb638bb125a36edc416558fd4c6 ) ) game ( @@ -22894,6 +23754,12 @@ game ( rom ( name "CutThroat Island (USA, Europe).gb" size 262144 crc eebdd360 sha1 5e99ea51b383cdcd53874eb027ebd59d2a3156b9 flags verified ) ) +game ( + name "Cyber Dreamscape Battle-Deckers 2199 (World) (Aftermarket) (Unl)" + description "Cyber Dreamscape Battle-Deckers 2199 (World) (Aftermarket) (Unl)" + rom ( name "Cyber Dreamscape Battle-Deckers 2199 (World) (Aftermarket) (Unl).gb" size 1048576 crc e3a78253 sha1 45c9c6a7a4ec985146a4a616a49dba45decc6d3e ) +) + game ( name "Cyraid (USA)" description "Cyraid (USA)" @@ -22949,21 +23815,15 @@ game ( ) game ( - name "Dangan (World) (v1.1) (Aftermarket) (Homebrew)" - description "Dangan (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Dangan (World) (v1.1) (Aftermarket) (Homebrew).gb" size 262144 crc 5359d6db sha1 10029774046dabec2d8c0533caf94091f6e19071 ) + name "Dangan GB (World) (v1.1) (Aftermarket) (Unl)" + description "Dangan GB (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Dangan GB (World) (v1.1) (Aftermarket) (Unl).gb" size 262144 crc 5359d6db sha1 10029774046dabec2d8c0533caf94091f6e19071 ) ) game ( - name "Dangan (World) (v1.0) (Aftermarket) (Homebrew)" - description "Dangan (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Dangan (World) (v1.0) (Aftermarket) (Homebrew).gb" size 262144 crc daa59c9c sha1 8375d845fcfe4c236cd68f3d56a290f8c7b76c06 ) -) - -game ( - name "Dark Winter Wander, A (World) (Aftermarket) (Homebrew)" - description "Dark Winter Wander, A (World) (Aftermarket) (Homebrew)" - rom ( name "Dark Winter Wander, A (World) (Aftermarket) (Homebrew).gb" size 1048576 crc df19aa9f sha1 412f18ba08f2f2a2afbf3bfb5281e360d7aba31d ) + name "Dangan GB (World) (Aftermarket) (Unl)" + description "Dangan GB (World) (Aftermarket) (Unl)" + rom ( name "Dangan GB (World) (Aftermarket) (Unl).gb" size 262144 crc daa59c9c sha1 8375d845fcfe4c236cd68f3d56a290f8c7b76c06 ) ) game ( @@ -22975,7 +23835,7 @@ game ( game ( name "Darkwing Duck (Europe)" description "Darkwing Duck (Europe)" - rom ( name "Darkwing Duck (Europe).gb" size 131072 crc be975b4f sha1 4e51919597aa72dd32182f9afee34f148036655f ) + rom ( name "Darkwing Duck (Europe).gb" size 131072 crc be975b4f sha1 4e51919597aa72dd32182f9afee34f148036655f flags verified ) ) game ( @@ -22997,9 +23857,15 @@ game ( ) game ( - name "Dash (World) (Aftermarket) (Homebrew)" - description "Dash (World) (Aftermarket) (Homebrew)" - rom ( name "Dash (World) (Aftermarket) (Homebrew).gb" size 262144 crc 73868683 sha1 c1ffe7c25a34d65ed166293bc7d2b48b65ca922b ) + name "Darkwing Duck (USA) (Beta)" + description "Darkwing Duck (USA) (Beta)" + rom ( name "Darkwing Duck (USA) (Beta).gb" size 131072 crc 311ade03 sha1 2883b8854529369cce4d473e71fa0193c7df02b6 ) +) + +game ( + name "Dash (World) (Aftermarket) (Unl)" + description "Dash (World) (Aftermarket) (Unl)" + rom ( name "Dash (World) (Aftermarket) (Unl).gb" size 262144 crc 73868683 sha1 c1ffe7c25a34d65ed166293bc7d2b48b65ca922b ) ) game ( @@ -23014,12 +23880,6 @@ game ( rom ( name "David Crane's The Rescue of Princess Blobette (USA).gb" size 65536 crc 8210a03f sha1 0a45d1b98646fd7832b5119b04bc8d6d6d0f657a ) ) -game ( - name "Dawn Will Come (World) (Aftermarket) (Homebrew)" - description "Dawn Will Come (World) (Aftermarket) (Homebrew)" - rom ( name "Dawn Will Come (World) (Aftermarket) (Homebrew).gb" size 2097152 crc bb64f51c sha1 1611ddfdb9af72f20ddeca4133d8eebd0f14e424 ) -) - game ( name "Days of Thunder (USA, Europe)" description "Days of Thunder (USA, Europe)" @@ -23039,15 +23899,21 @@ game ( ) game ( - name "Deadeus (World) (1.3.8) (Aftermarket) (Unl)" - description "Deadeus (World) (1.3.8) (Aftermarket) (Unl)" - rom ( name "Deadeus (World) (1.3.8) (Aftermarket) (Unl).gb" size 1048576 crc 7da95971 sha1 23cff594ef4b0bb21883b422940526c7fe81f1fd ) + name "Deadeus (World) (v1.3.8) (Aftermarket) (Unl)" + description "Deadeus (World) (v1.3.8) (Aftermarket) (Unl)" + rom ( name "Deadeus (World) (v1.3.8) (Aftermarket) (Unl).gb" size 1048576 crc 7da95971 sha1 23cff594ef4b0bb21883b422940526c7fe81f1fd flags verified ) ) game ( - name "Deadeus (World) (1.2.5) (Aftermarket) (Unl)" - description "Deadeus (World) (1.2.5) (Aftermarket) (Unl)" - rom ( name "Deadeus (World) (1.2.5) (Aftermarket) (Unl).gb" size 1048576 crc 9e2bf649 sha1 3feeba5c438880f70cdfdc4ea7e29f77e645e9be ) + name "Deadeus (World) (v1.2.5) (Aftermarket) (Unl)" + description "Deadeus (World) (v1.2.5) (Aftermarket) (Unl)" + rom ( name "Deadeus (World) (v1.2.5) (Aftermarket) (Unl).gb" size 1048576 crc 9e2bf649 sha1 3feeba5c438880f70cdfdc4ea7e29f77e645e9be flags verified ) +) + +game ( + name "Deadeus (World) (v1.1.0) (Aftermarket) (Unl)" + description "Deadeus (World) (v1.1.0) (Aftermarket) (Unl)" + rom ( name "Deadeus (World) (v1.1.0) (Aftermarket) (Unl).gb" size 1048576 crc 818a7db7 sha1 43a93dc6f7bef002271e583edaeaf2e7162b8af4 ) ) game ( @@ -23057,15 +23923,9 @@ game ( ) game ( - name "Deep Forest (World) (v1.1) (Aftermarket) (Homebrew)" - description "Deep Forest (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Deep Forest (World) (v1.1) (Aftermarket) (Homebrew).gb" size 1048576 crc 3ddf177d sha1 517302d20cb5140975e6cd1b3c495786b6390aaf ) -) - -game ( - name "Dennis (Europe)" - description "Dennis (Europe)" - rom ( name "Dennis (Europe).gb" size 131072 crc 896a30a8 sha1 9b5c289f25829534020951f84732177036837aea ) + name "Deep Forest (World) (v1.1) (Aftermarket) (Unl)" + description "Deep Forest (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Deep Forest (World) (v1.1) (Aftermarket) (Unl).gb" size 1048576 crc 3ddf177d sha1 517302d20cb5140975e6cd1b3c495786b6390aaf ) ) game ( @@ -23074,6 +23934,12 @@ game ( rom ( name "Dennis (Europe) (Beta) (1993-09-13).gb" size 131072 crc 807d34a4 sha1 fab382a28f9d7fefae7dc9a16bf86f309d89e037 ) ) +game ( + name "Dennis (Europe)" + description "Dennis (Europe)" + rom ( name "Dennis (Europe).gb" size 131072 crc 896a30a8 sha1 9b5c289f25829534020951f84732177036837aea ) +) + game ( name "Dennis the Menace (USA)" description "Dennis the Menace (USA)" @@ -23105,9 +23971,9 @@ game ( ) game ( - name "DiaMaze (World) (Aftermarket) (Homebrew)" - description "DiaMaze (World) (Aftermarket) (Homebrew)" - rom ( name "DiaMaze (World) (Aftermarket) (Homebrew).gb" size 262144 crc 956fa901 sha1 f41b98ac4669920ffede1736ddbd9e1f62d4cb0d ) + name "DiaMaze (World) (Aftermarket) (Unl)" + description "DiaMaze (World) (Aftermarket) (Unl)" + rom ( name "DiaMaze (World) (Aftermarket) (Unl).gb" size 262144 crc 956fa901 sha1 f41b98ac4669920ffede1736ddbd9e1f62d4cb0d ) ) game ( @@ -23128,6 +23994,12 @@ game ( rom ( name "Dig Dug (USA).gb" size 131072 crc 6c742478 sha1 951753904389332412d4b0a80b48d7ac61a494fc ) ) +game ( + name "Dijon Gameboy (World) (En,Fr) (Demo) (Aftermarket) (Unl)" + description "Dijon Gameboy (World) (En,Fr) (Demo) (Aftermarket) (Unl)" + rom ( name "Dijon Gameboy (World) (En,Fr) (Demo) (Aftermarket) (Unl).gb" size 1048576 crc b230b782 sha1 f1796dcbfb6f0f5e01c60222c376cc1c46945806 ) +) + game ( name "Dino Breeder (Japan) (SGB Enhanced)" description "Dino Breeder (Japan) (SGB Enhanced)" @@ -23147,9 +24019,9 @@ game ( ) game ( - name "Dino's Offline Adventure (World) (Aftermarket) (Homebrew)" - description "Dino's Offline Adventure (World) (Aftermarket) (Homebrew)" - rom ( name "Dino's Offline Adventure (World) (Aftermarket) (Homebrew).gb" size 32768 crc d6bd0e6a sha1 6d11c145606f8e7ab25b2b07c299e36c8b442d23 ) + name "Dino's Offline Adventure (World) (Aftermarket) (Unl)" + description "Dino's Offline Adventure (World) (Aftermarket) (Unl)" + rom ( name "Dino's Offline Adventure (World) (Aftermarket) (Unl).gb" size 32768 crc d6bd0e6a sha1 6d11c145606f8e7ab25b2b07c299e36c8b442d23 ) ) game ( @@ -23165,81 +24037,63 @@ game ( ) game ( - name "Disco Elysium - Game Boy Edition (World) (Aftermarket) (Homebrew)" - description "Disco Elysium - Game Boy Edition (World) (Aftermarket) (Homebrew)" - rom ( name "Disco Elysium - Game Boy Edition (World) (Aftermarket) (Homebrew).gb" size 1048576 crc ef349515 sha1 06fe25086432c82f1e4b4c44473dd5b487a8af05 ) + name "DMG Deals Damage (World) (Aftermarket) (Unl)" + description "DMG Deals Damage (World) (Aftermarket) (Unl)" + rom ( name "DMG Deals Damage (World) (Aftermarket) (Unl).gb" size 32768 crc 250e0cbd sha1 a15539199e4b6bd2a71d1ac0e7c61ae4f19a65e7 flags verified ) ) game ( - name "DMG Deals Damage (World) (Aftermarket) (Homebrew)" - description "DMG Deals Damage (World) (Aftermarket) (Homebrew)" - rom ( name "DMG Deals Damage (World) (Aftermarket) (Homebrew).gb" size 32768 crc 250e0cbd sha1 a15539199e4b6bd2a71d1ac0e7c61ae4f19a65e7 ) + name "Do I Pass (World) (En) (Demo) (Aftermarket) (Unl)" + description "Do I Pass (World) (En) (Demo) (Aftermarket) (Unl)" + rom ( name "Do I Pass (World) (En) (Demo) (Aftermarket) (Unl).gb" size 1048576 crc f339fa82 sha1 bdbc082017bdf2e4caa84e7d00dad9707727e9d4 ) ) game ( - name "DMG Express (World) (v3.0.1) (Aftermarket) (Homebrew)" - description "DMG Express (World) (v3.0.1) (Aftermarket) (Homebrew)" - rom ( name "DMG Express (World) (v3.0.1) (Aftermarket) (Homebrew).gb" size 262144 crc 56dbbbd4 sha1 07babaa6980fdd6c6470291511280008bfdec26c ) + name "Do I Pass (World) (En) (v1.4) (Aftermarket) (Unl)" + description "Do I Pass (World) (En) (v1.4) (Aftermarket) (Unl)" + rom ( name "Do I Pass (World) (En) (v1.4) (Aftermarket) (Unl).gb" size 1048576 crc cfb44d68 sha1 6dde71bbec8b807af5132d1ef2e99c6bb6af3a1c ) ) game ( - name "DMG Express (World) (v2.0.1) (Aftermarket) (Homebrew)" - description "DMG Express (World) (v2.0.1) (Aftermarket) (Homebrew)" - rom ( name "DMG Express (World) (v2.0.1) (Aftermarket) (Homebrew).gbc" size 262144 crc 4c2364a4 sha1 3077afd1920ea041dd2631834276a6234076b485 flags verified ) + name "Do I Pass (World) (En) (v1.4) (Web) (Aftermarket) (Unl)" + description "Do I Pass (World) (En) (v1.4) (Web) (Aftermarket) (Unl)" + rom ( name "Do I Pass (World) (En) (v1.4) (Web) (Aftermarket) (Unl).gb" size 1048576 crc 62e0c3a2 sha1 e1b516e472e0c681b4ad1c7f4aeda55c91e7f340 ) ) game ( - name "Do I Pass (World) (Demo) (Aftermarket) (Homebrew)" - description "Do I Pass (World) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Do I Pass (World) (Demo) (Aftermarket) (Homebrew).gb" size 1048576 crc f339fa82 sha1 bdbc082017bdf2e4caa84e7d00dad9707727e9d4 ) + name "Do I Pass (World) (Fr) (v1.4.2) (Aftermarket) (Unl)" + description "Do I Pass (World) (Fr) (v1.4.2) (Aftermarket) (Unl)" + rom ( name "Do I Pass (World) (Fr) (v1.4.2) (Aftermarket) (Unl).gb" size 1048576 crc e393d4aa sha1 d45dfcab4a76b62ea1e10730d01f755e12137484 ) ) game ( - name "Do I Pass (World) (v1.4) (Aftermarket) (Homebrew)" - description "Do I Pass (World) (v1.4) (Aftermarket) (Homebrew)" - rom ( name "Do I Pass (World) (v1.4) (Aftermarket) (Homebrew).gb" size 1048576 crc cfb44d68 sha1 6dde71bbec8b807af5132d1ef2e99c6bb6af3a1c ) + name "Do I Pass (World) (En) (v1.5) (Aftermarket) (Unl)" + description "Do I Pass (World) (En) (v1.5) (Aftermarket) (Unl)" + rom ( name "Do I Pass (World) (En) (v1.5) (Aftermarket) (Unl).gb" size 1048576 crc 3890e0a4 sha1 6998e1bbf2ccb9db3d661ddac2d7edf7571d0af7 ) ) game ( - name "Do I Pass (World) (v1.4) (Web) (Aftermarket) (Homebrew)" - description "Do I Pass (World) (v1.4) (Web) (Aftermarket) (Homebrew)" - rom ( name "Do I Pass (World) (v1.4) (Web) (Aftermarket) (Homebrew).gb" size 1048576 crc 62e0c3a2 sha1 e1b516e472e0c681b4ad1c7f4aeda55c91e7f340 ) + name "Doctor GB Card 16M Loader (World) (Unl)" + description "Doctor GB Card 16M Loader (World) (Unl)" + rom ( name "Doctor GB Card 16M Loader (World) (Unl).gb" size 32768 crc 1bddf36f sha1 c298eacc0c73e648e81fbf5192aec3b6a438e053 ) ) game ( - name "Do I Pass (World) (Fr) (v1.4.2) (Aftermarket) (Homebrew)" - description "Do I Pass (World) (Fr) (v1.4.2) (Aftermarket) (Homebrew)" - rom ( name "Do I Pass (World) (Fr) (v1.4.2) (Aftermarket) (Homebrew).gb" size 1048576 crc e393d4aa sha1 d45dfcab4a76b62ea1e10730d01f755e12137484 ) + name "Doctor GB Card 4M (World) (Unl)" + description "Doctor GB Card 4M (World) (Unl)" + rom ( name "Doctor GB Card 4M (World) (Unl).gb" size 524288 crc 5d2e8cff sha1 43962a7459c8ccc0e5988060abd0f8668f30dfde ) ) game ( - name "Do I Pass (World) (v1.5) (Aftermarket) (Homebrew)" - description "Do I Pass (World) (v1.5) (Aftermarket) (Homebrew)" - rom ( name "Do I Pass (World) (v1.5) (Aftermarket) (Homebrew).gb" size 1048576 crc 3890e0a4 sha1 6998e1bbf2ccb9db3d661ddac2d7edf7571d0af7 ) + name "Doctor GB Card Demo (World) (Demo) (Unl)" + description "Doctor GB Card Demo (World) (Demo) (Unl)" + rom ( name "Doctor GB Card Demo (World) (Demo) (Unl).gb" size 32768 crc b5dfdc26 sha1 1d403b254971faa5834bc48adfd42cc0bbed3fe4 ) ) game ( - name "Doctor GB Card 16M Loader (World) (Homebrew)" - description "Doctor GB Card 16M Loader (World) (Homebrew)" - rom ( name "Doctor GB Card 16M Loader (World) (Homebrew).gb" size 32768 crc 1bddf36f sha1 c298eacc0c73e648e81fbf5192aec3b6a438e053 ) -) - -game ( - name "Doctor GB Card 4M (World) (Homebrew)" - description "Doctor GB Card 4M (World) (Homebrew)" - rom ( name "Doctor GB Card 4M (World) (Homebrew).gb" size 524288 crc 5d2e8cff sha1 43962a7459c8ccc0e5988060abd0f8668f30dfde ) -) - -game ( - name "Doctor GB Card Demo (World) (Demo) (Homebrew) (Alt)" - description "Doctor GB Card Demo (World) (Demo) (Homebrew) (Alt)" - rom ( name "Doctor GB Card Demo (World) (Demo) (Homebrew) (Alt).gb" size 32768 crc 3592390b sha1 a6e3b81b8664f41eb18770cd5757ed4d8338be54 ) -) - -game ( - name "Doctor GB Card Demo (World) (Demo) (Homebrew)" - description "Doctor GB Card Demo (World) (Demo) (Homebrew)" - rom ( name "Doctor GB Card Demo (World) (Demo) (Homebrew).gb" size 32768 crc b5dfdc26 sha1 1d403b254971faa5834bc48adfd42cc0bbed3fe4 ) + name "Doctor GB Card Demo (World) (Demo) (Unl) (Alt)" + description "Doctor GB Card Demo (World) (Demo) (Unl) (Alt)" + rom ( name "Doctor GB Card Demo (World) (Demo) (Unl) (Alt).gb" size 32768 crc 3592390b sha1 a6e3b81b8664f41eb18770cd5757ed4d8338be54 ) ) game ( @@ -23249,15 +24103,15 @@ game ( ) game ( - name "Dog's Muck Island (World) (Aftermarket) (Homebrew)" - description "Dog's Muck Island (World) (Aftermarket) (Homebrew)" - rom ( name "Dog's Muck Island (World) (Aftermarket) (Homebrew).gb" size 262144 crc 79a7a06c sha1 eb4cea3b9db770bf3b586578af1ad7427d88ee8e ) + name "Dog's Muck Island (World) (Aftermarket) (Unl)" + description "Dog's Muck Island (World) (Aftermarket) (Unl)" + rom ( name "Dog's Muck Island (World) (Aftermarket) (Unl).gb" size 262144 crc 79a7a06c sha1 eb4cea3b9db770bf3b586578af1ad7427d88ee8e ) ) game ( - name "Don't Forget About Me (World) (Prototype) (Aftermarket) (Homebrew)" - description "Don't Forget About Me (World) (Prototype) (Aftermarket) (Homebrew)" - rom ( name "Don't Forget About Me (World) (Prototype) (Aftermarket) (Homebrew).gb" size 524288 crc 52cf7153 sha1 74e6246405dd52d4c5c2eabc417946550c637164 ) + name "Don't Call Me Mama But Yes I Am Your Mama (World) (v2.0) (Aftermarket) (Unl)" + description "Don't Call Me Mama But Yes I Am Your Mama (World) (v2.0) (Aftermarket) (Unl)" + rom ( name "Don't Call Me Mama But Yes I Am Your Mama (World) (v2.0) (Aftermarket) (Unl).gb" size 1048576 crc 83247308 sha1 4579eaa45e2bf8f17f4dc99bdfb0b98270b871f5 ) ) game ( @@ -23530,6 +24384,12 @@ game ( rom ( name "Dragon Ball Z 3 (USA) (SGB Enhanced) (Unl).gb" size 1048576 crc 71b8ea17 sha1 c43eb3906f77dda5fee94a0fce0b6d783461238c ) ) +game ( + name "Dragon Battle (World) (Demo) (Aftermarket) (Unl)" + description "Dragon Battle (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Dragon Battle (World) (Demo) (Aftermarket) (Unl).gb" size 4194304 crc c1e1e52c sha1 c5ac56e266c421a1c5b82de46859a44f75d03359 ) +) + game ( name "Dragon Slayer Gaiden - Nemuri no Oukan (Japan)" description "Dragon Slayer Gaiden - Nemuri no Oukan (Japan)" @@ -23665,7 +24525,7 @@ game ( game ( name "DX Bakenou Z (Japan) (Rev 1)" description "DX Bakenou Z (Japan) (Rev 1)" - rom ( name "DX Bakenou Z (Japan) (Rev 1).gb" size 131072 crc fadfd0f6 sha1 6e2b9b21ea7d8d482be1f17722a579f720f2029d ) + rom ( name "DX Bakenou Z (Japan) (Rev 1).gb" size 131072 crc fadfd0f6 sha1 6e2b9b21ea7d8d482be1f17722a579f720f2029d flags verified ) ) game ( @@ -23677,7 +24537,7 @@ game ( game ( name "Earthworm Jim (Europe)" description "Earthworm Jim (Europe)" - rom ( name "Earthworm Jim (Europe).gb" size 262144 crc b1a7a008 sha1 4249abe39285b02ccb0e739b5a2cf96ace1281ff ) + rom ( name "Earthworm Jim (Europe).gb" size 262144 crc b1a7a008 sha1 4249abe39285b02ccb0e739b5a2cf96ace1281ff flags verified ) ) game ( @@ -23686,6 +24546,12 @@ game ( rom ( name "Earthworm Jim (USA).gb" size 262144 crc 259ff267 sha1 f5d3085de17a5181c07739e49be7637faa5ff932 ) ) +game ( + name "Eclipse (Europe) (Proto)" + description "Eclipse (Europe) (Proto)" + rom ( name "Eclipse (Europe) (Proto).gb" size 65536 crc 6b507efd sha1 de02a34675a57d450284103681951436a4c830cd ) +) + game ( name "Edd the Duck (Europe) (Proto)" description "Edd the Duck (Europe) (Proto)" @@ -23698,6 +24564,12 @@ game ( rom ( name "Eddie's Puzzle Time (USA) (Proto).gb" size 65536 crc f2600f02 sha1 cd2695295831737d0f8a7eb825bbfe870b9c0bfd ) ) +game ( + name "Elden Ring GB (World) (Aftermarket) (Unl)" + description "Elden Ring GB (World) (Aftermarket) (Unl)" + rom ( name "Elden Ring GB (World) (Aftermarket) (Unl).gb" size 524288 crc e7a420f3 sha1 2e0bec6acf1a94ae3f2f6cf2040323862933d95a ) +) + game ( name "Elevator Action (Japan)" description "Elevator Action (Japan)" @@ -23759,9 +24631,9 @@ game ( ) game ( - name "F-Zero - Project (World) (Aftermarket) (Homebrew)" - description "F-Zero - Project (World) (Aftermarket) (Homebrew)" - rom ( name "F-Zero - Project (World) (Aftermarket) (Homebrew).gb" size 1048576 crc 4c707059 sha1 5b823ee17691d286a45f0667cddd59ccaaab5d8b ) + name "F-Zero - Project (World) (Aftermarket) (Unl)" + description "F-Zero - Project (World) (Aftermarket) (Unl)" + rom ( name "F-Zero - Project (World) (Aftermarket) (Unl).gb" size 1048576 crc 4c707059 sha1 5b823ee17691d286a45f0667cddd59ccaaab5d8b ) ) game ( @@ -23785,7 +24657,13 @@ game ( game ( name "Faceball 2000 (USA)" description "Faceball 2000 (USA)" - rom ( name "Faceball 2000 (USA).gb" size 131072 crc 7d890cd0 sha1 b0bd15bace04e0a3eb89773f231ac3a532181a0a ) + rom ( name "Faceball 2000 (USA).gb" size 131072 crc 7d890cd0 sha1 b0bd15bace04e0a3eb89773f231ac3a532181a0a flags verified ) +) + +game ( + name "Fairy-chan (World) (v0.1.4) (Demo) (Aftermarket) (Unl)" + description "Fairy-chan (World) (v0.1.4) (Demo) (Aftermarket) (Unl)" + rom ( name "Fairy-chan (World) (v0.1.4) (Demo) (Aftermarket) (Unl).gb" size 262144 crc 4f04cdfc sha1 591980cb5e17104d826c2a915f53bfc8a21affca ) ) game ( @@ -23819,9 +24697,9 @@ game ( ) game ( - name "Farm, The (World) (Aftermarket) (Homebrew)" - description "Farm, The (World) (Aftermarket) (Homebrew)" - rom ( name "Farm, The (World) (Aftermarket) (Homebrew).gb" size 524288 crc fbc1b5e8 sha1 d0fe06920f7e771d76507f60881904370ffbc145 ) + name "Farm, The (World) (Aftermarket) (Unl)" + description "Farm, The (World) (Aftermarket) (Unl)" + rom ( name "Farm, The (World) (Aftermarket) (Unl).gb" size 524288 crc fbc1b5e8 sha1 d0fe06920f7e771d76507f60881904370ffbc145 ) ) game ( @@ -23956,6 +24834,12 @@ game ( rom ( name "Final Fantasy Legend, The (USA).gb" size 131072 crc 8046148f sha1 901dfc83c72e172d35a376835807fc788444a9bb flags verified ) ) +game ( + name "Final Fantasy XI Adventure (World) (Aftermarket) (Unl)" + description "Final Fantasy XI Adventure (World) (Aftermarket) (Unl)" + rom ( name "Final Fantasy XI Adventure (World) (Aftermarket) (Unl).gb" size 1048576 crc 6cfb4669 sha1 339fd673509a5ac8f25426af25b4ccc96e8d2880 ) +) + game ( name "Final Reverse (Japan)" description "Final Reverse (Japan)" @@ -23963,9 +24847,9 @@ game ( ) game ( - name "Finders Keepers (World) (Aftermarket) (Homebrew)" - description "Finders Keepers (World) (Aftermarket) (Homebrew)" - rom ( name "Finders Keepers (World) (Aftermarket) (Homebrew).gb" size 524288 crc 6a98ac61 sha1 e40dd804388df8c08d3890d79eeafd8542cc8805 ) + name "Finders Keepers (World) (Aftermarket) (Unl)" + description "Finders Keepers (World) (Aftermarket) (Unl)" + rom ( name "Finders Keepers (World) (Aftermarket) (Unl).gb" size 524288 crc 6a98ac61 sha1 e40dd804388df8c08d3890d79eeafd8542cc8805 ) ) game ( @@ -23987,9 +24871,9 @@ game ( ) game ( - name "Fix My Heart (World) (Aftermarket) (Homebrew)" - description "Fix My Heart (World) (Aftermarket) (Homebrew)" - rom ( name "Fix My Heart (World) (Aftermarket) (Homebrew).gb" size 524288 crc 507f9ea2 sha1 28ad64e379dc60d6e1c2617e073f6361c0feb475 ) + name "Flappy Special (Japan)" + description "Flappy Special (Japan)" + rom ( name "Flappy Special (Japan).gb" size 32768 crc 3b6cdda4 sha1 6517aee7caa2fa60750005ef1dacaeaecee7c2f6 ) ) game ( @@ -23998,24 +24882,12 @@ game ( rom ( name "Flappy Special (USA) (Proto).gb" size 32768 crc 617d0d9f sha1 75347d9f708da85487b779ed79b9c1e84954020d ) ) -game ( - name "Flappy Special (Japan)" - description "Flappy Special (Japan)" - rom ( name "Flappy Special (Japan).gb" size 32768 crc 3b6cdda4 sha1 6517aee7caa2fa60750005ef1dacaeaecee7c2f6 ) -) - game ( name "Flash, The (USA, Europe)" description "Flash, The (USA, Europe)" rom ( name "Flash, The (USA, Europe).gb" size 131072 crc 6deb1f06 sha1 f7e5701e6fa8fe4440988d1207517668c35088c6 ) ) -game ( - name "Flashin' (World) (v3.0) (Aftermarket) (Homebrew)" - description "Flashin' (World) (v3.0) (Aftermarket) (Homebrew)" - rom ( name "Flashin' (World) (v3.0) (Aftermarket) (Homebrew).gb" size 1048576 crc fcc05ec4 sha1 64d31f34e189b3af08bf0c659a93f71dbf83ef71 ) -) - game ( name "Fleet Commander VS. (Japan)" description "Fleet Commander VS. (Japan)" @@ -24053,9 +24925,9 @@ game ( ) game ( - name "Flooder (World) (Aftermarket) (Homebrew)" - description "Flooder (World) (Aftermarket) (Homebrew)" - rom ( name "Flooder (World) (Aftermarket) (Homebrew).gb" size 32768 crc 253dcbe0 sha1 8fdcd8b02604ac5259fb6aa80e5ba67a03c861fb ) + name "Fly O'Clock (World) (Aftermarket) (Unl)" + description "Fly O'Clock (World) (Aftermarket) (Unl)" + rom ( name "Fly O'Clock (World) (Aftermarket) (Unl).gb" size 32768 crc 93df7f55 sha1 83dc8498bdbabc14a8f81a715c9da19970c1f0b9 ) ) game ( @@ -24076,12 +24948,6 @@ game ( rom ( name "Foreman for Real (USA, Europe).gb" size 262144 crc 77083ae0 sha1 7b088c7b3a0ad275d340ca27f64a99c1bd6c34e6 ) ) -game ( - name "Forest of Fallen Knights (World) (Aftermarket) (Homebrew)" - description "Forest of Fallen Knights (World) (Aftermarket) (Homebrew)" - rom ( name "Forest of Fallen Knights (World) (Aftermarket) (Homebrew).gb" size 524288 crc 4c21e563 sha1 f6f84f1a44d41fa7d26a9195ddf791fae53dfcdf ) -) - game ( name "Fortified Zone (USA, Europe)" description "Fortified Zone (USA, Europe)" @@ -24100,12 +24966,6 @@ game ( rom ( name "Franky, Joe & Dirk - On the Tiles (Europe) (En,Fr,De,Es,It,Nl).gb" size 131072 crc caf5b372 sha1 b7e292cfd34d64546f158e548afa92efaf8c2acd ) ) -game ( - name "Friday the 13th - The GB Game (World) (Aftermarket) (Homebrew)" - description "Friday the 13th - The GB Game (World) (Aftermarket) (Homebrew)" - rom ( name "Friday the 13th - The GB Game (World) (Aftermarket) (Homebrew).gb" size 1048576 crc 7543586a sha1 397821751ac6464582f61566f3a7c731a46b24ba ) -) - game ( name "Frisky Tom (Japan) (SGB Enhanced)" description "Frisky Tom (Japan) (SGB Enhanced)" @@ -24154,6 +25014,12 @@ game ( rom ( name "Fushigi no Dungeon - Fuurai no Shiren GB - Tsukikage Mura no Kaibutsu (Japan) (SGB Enhanced).gb" size 524288 crc 2962afb4 sha1 920ef94c05ac741047a266cb1668c881eab2937c flags verified ) ) +game ( + name "Fydo's Magic Tiles (World) (2022-09-01) (Aftermarket) (Unl)" + description "Fydo's Magic Tiles (World) (2022-09-01) (Aftermarket) (Unl)" + rom ( name "Fydo's Magic Tiles (World) (2022-09-01) (Aftermarket) (Unl).gb" size 32768 crc 36e2ca02 sha1 fd985703b296dd0bf74225c72155ea9e51dd6853 ) +) + game ( name "G Arms - Operation Gundam (Japan)" description "G Arms - Operation Gundam (Japan)" @@ -24161,15 +25027,15 @@ game ( ) game ( - name "G-Man (World) (Aftermarket) (Homebrew)" - description "G-Man (World) (Aftermarket) (Homebrew)" - rom ( name "G-Man (World) (Aftermarket) (Homebrew).gb" size 524288 crc 7296da69 sha1 fdc9933d46a063575c175453b1da8042fd28b135 ) + name "G-Man (World) (Aftermarket) (Unl)" + description "G-Man (World) (Aftermarket) (Unl)" + rom ( name "G-Man (World) (Aftermarket) (Unl).gb" size 524288 crc 7296da69 sha1 fdc9933d46a063575c175453b1da8042fd28b135 ) ) game ( - name "G-ZERO (World) (v2.6) (Aftermarket) (Homebrew)" - description "G-ZERO (World) (v2.6) (Aftermarket) (Homebrew)" - rom ( name "G-ZERO (World) (v2.6) (Aftermarket) (Homebrew).gb" size 65536 crc 7dd0c878 sha1 929d25a612308614ac3ac2ee5a19a9cd4a9968d6 ) + name "G-ZERO (World) (v2.6) (Aftermarket) (Unl)" + description "G-ZERO (World) (v2.6) (Aftermarket) (Unl)" + rom ( name "G-ZERO (World) (v2.6) (Aftermarket) (Unl).gb" size 65536 crc 7dd0c878 sha1 929d25a612308614ac3ac2ee5a19a9cd4a9968d6 ) ) game ( @@ -24208,12 +25074,6 @@ game ( rom ( name "Game Boy Camera (USA, Europe) (SGB Enhanced).gb" size 1048576 crc 4640909f sha1 461c3c37ed270681e3e94053efb21504b600aef5 flags verified ) ) -game ( - name "Game Boy Camera Gallery 2022, The (World) (Aftermarket) (Homebrew)" - description "Game Boy Camera Gallery 2022, The (World) (Aftermarket) (Homebrew)" - rom ( name "Game Boy Camera Gallery 2022, The (World) (Aftermarket) (Homebrew).gb" size 524288 crc f1948966 sha1 14849ab5831c71949ec3a1fe7657050057d2cf29 ) -) - game ( name "Game Boy Camera Gold (USA) (SGB Enhanced)" description "Game Boy Camera Gold (USA) (SGB Enhanced)" @@ -24233,9 +25093,15 @@ game ( ) game ( - name "Game Boy Digital Sampling Oscilloscope (Europe) (v3.6) (Unl)" - description "Game Boy Digital Sampling Oscilloscope (Europe) (v3.6) (Unl)" - rom ( name "Game Boy Digital Sampling Oscilloscope (Europe) (v3.6) (Unl).gb" size 32768 crc 572ea59c sha1 68128bd8b01970054590a88b785d553456b68ec1 ) + name "Game Boy Digital Sampling Oscilloscope (Europe) (Unl)" + description "Game Boy Digital Sampling Oscilloscope (Europe) (Unl)" + rom ( name "Game Boy Digital Sampling Oscilloscope (Europe) (Unl).gb" size 32768 crc 572ea59c sha1 68128bd8b01970054590a88b785d553456b68ec1 ) +) + +game ( + name "Game Boy Digital Sampling Oscilloscope (Europe) (Demo) (Unl)" + description "Game Boy Digital Sampling Oscilloscope (Europe) (Demo) (Unl)" + rom ( name "Game Boy Digital Sampling Oscilloscope (Europe) (Demo) (Unl).gb" size 32768 crc a800444b sha1 db3e76bced7bd9844aedf23345c4307403006600 ) ) game ( @@ -24316,6 +25182,12 @@ game ( rom ( name "Game of Harmony, The (USA).gb" size 32768 crc b0074acb sha1 b0bc752e3ad25fcb83d8ca04a82a0f5e35381db2 ) ) +game ( + name "GameBoy WORDLE (World) (Aftermarket) (Unl)" + description "GameBoy WORDLE (World) (Aftermarket) (Unl)" + rom ( name "GameBoy WORDLE (World) (Aftermarket) (Unl).gb" size 32768 crc cc971c0f sha1 ba93939b93ab3f3aa5f7aa451d50d9b89220adbc ) +) + game ( name "Gamera - Daikaijuu Kuuchuu Kessen (Japan) (SGB Enhanced)" description "Gamera - Daikaijuu Kuuchuu Kessen (Japan) (SGB Enhanced)" @@ -24323,9 +25195,9 @@ game ( ) game ( - name "GameShark (USA) (Unl)" - description "GameShark (USA) (Unl)" - rom ( name "GameShark (USA) (Unl).gb" size 131072 crc d6909596 sha1 09a6dae5e5faae1c4b5cf20e1b913b1c5e72297e ) + name "GameShark (USA) (Unl) [b]" + description "GameShark (USA) (Unl) [b]" + rom ( name "GameShark (USA) (Unl) [b].gb" size 131072 crc d6909596 sha1 09a6dae5e5faae1c4b5cf20e1b913b1c5e72297e flags baddump ) ) game ( @@ -24424,66 +25296,6 @@ game ( rom ( name "GB Pachi-Slot Hisshouhou! Jr. (Japan).gb" size 131072 crc a2e210e9 sha1 7636799f5a57d22cf579bb687be5bb9fedddd0ca ) ) -game ( - name "GB-Wordyl (World) (Pt-BR) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Pt-BR) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Pt-BR) (Aftermarket) (Homebrew).gb" size 32768 crc f20c0097 sha1 691af25434a09931a302ced52c757d28b9b06619 ) -) - -game ( - name "GB-Wordyl (World) (Ca) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Ca) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Ca) (Aftermarket) (Homebrew).gb" size 32768 crc 164999eb sha1 197d3d194d4cb6cae9a358f7fb53d6de649e7c5f ) -) - -game ( - name "GB-Wordyl (World) (De) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (De) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (De) (Aftermarket) (Homebrew).gb" size 32768 crc 60b075d1 sha1 0a66254b2327b48657de64d6102ac05f1e8700e7 ) -) - -game ( - name "GB-Wordyl (World) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Aftermarket) (Homebrew).gb" size 32768 crc 8780e125 sha1 7163bfbaa2cae2f9d41c472128f69a4fa5879180 ) -) - -game ( - name "GB-Wordyl (World) (Es) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Es) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Es) (Aftermarket) (Homebrew).gb" size 32768 crc 1a169897 sha1 0636b968e8e24fe7c1910f61db6e94fa84824494 ) -) - -game ( - name "GB-Wordyl (World) (Fr) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Fr) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Fr) (Aftermarket) (Homebrew).gb" size 32768 crc 593965ff sha1 75d566045a680aaed4d40b83b6418cbfab5b4422 ) -) - -game ( - name "GB-Wordyl (World) (It) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (It) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (It) (Aftermarket) (Homebrew).gb" size 32768 crc d81ab567 sha1 1dfd3c4508ffb6598662bcf1b16ec109a9282dd5 ) -) - -game ( - name "GB-Wordyl (World) (Cornish Edition) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Cornish Edition) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Cornish Edition) (Aftermarket) (Homebrew).gb" size 32768 crc f795689c sha1 9a332127182e8155d1a3dc53e1382a6c9dde6aeb ) -) - -game ( - name "GB-Wordyl (World) (Es-XL) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Es-XL) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Es-XL) (Aftermarket) (Homebrew).gb" size 32768 crc 660ed37b sha1 0792fbef010cac21c12cbcb8b3c85b3af30faec4 ) -) - -game ( - name "GB-Wordyl (World) (Nl) (Aftermarket) (Homebrew)" - description "GB-Wordyl (World) (Nl) (Aftermarket) (Homebrew)" - rom ( name "GB-Wordyl (World) (Nl) (Aftermarket) (Homebrew).gb" size 32768 crc 6dc4faaa sha1 7617083f9b13b2f95bdf1b0b327ffb4f8ccbe3c9 ) -) - game ( name "GBKiss Mini Games (Japan)" description "GBKiss Mini Games (Japan)" @@ -24514,6 +25326,18 @@ game ( rom ( name "Gem Gem (Japan).gb" size 65536 crc a64a8710 sha1 90a29d7a56f64b596cda1c64c8998b63d12c321e ) ) +game ( + name "Genesis (World) (Aftermarket) (Unl)" + description "Genesis (World) (Aftermarket) (Unl)" + rom ( name "Genesis (World) (Aftermarket) (Unl).gb" size 65536 crc 74b3ec78 sha1 ca43f82d73ba0b3e43ec17f6bc6761c09ca23626 ) +) + +game ( + name "Genesis II (World) (Demo) (Aftermarket) (Unl)" + description "Genesis II (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Genesis II (World) (Demo) (Aftermarket) (Unl).gb" size 262144 crc d7aec1cc sha1 9700ea1278850df004ded7553253cfdd354f4ada ) +) + game ( name "Genjin Collection (Japan) (SGB Enhanced)" description "Genjin Collection (Japan) (SGB Enhanced)" @@ -24551,9 +25375,9 @@ game ( ) game ( - name "Ghost Town (World) (Aftermarket) (Homebrew)" - description "Ghost Town (World) (Aftermarket) (Homebrew)" - rom ( name "Ghost Town (World) (Aftermarket) (Homebrew).gb" size 262144 crc 2d27cdf2 sha1 af526273cdaa6423b92d0484fb27af56fe355a5d ) + name "Ghost Town (World) (Aftermarket) (Unl)" + description "Ghost Town (World) (Aftermarket) (Unl)" + rom ( name "Ghost Town (World) (Aftermarket) (Unl).gb" size 262144 crc 2d27cdf2 sha1 af526273cdaa6423b92d0484fb27af56fe355a5d ) ) game ( @@ -24586,6 +25410,18 @@ game ( rom ( name "Ginga - Card & Puzzle Collection (Japan) (En,Ja).gb" size 65536 crc 87d0637b sha1 14f4f14caee081dceadb9d31ae26fd8968c432ea ) ) +game ( + name "Glory Hunters - Chapter 1 (World) (v0.1) (Demo) (Aftermarket) (Unl)" + description "Glory Hunters - Chapter 1 (World) (v0.1) (Demo) (Aftermarket) (Unl)" + rom ( name "Glory Hunters - Chapter 1 (World) (v0.1) (Demo) (Aftermarket) (Unl).gb" size 2097152 crc 4b19366d sha1 77f3b561bf28a81f38dbedc351752e10ff4c23dc ) +) + +game ( + name "Glory Hunters - Chapter 1 (World) (v0.2) (Demo) (Aftermarket) (Unl)" + description "Glory Hunters - Chapter 1 (World) (v0.2) (Demo) (Aftermarket) (Unl)" + rom ( name "Glory Hunters - Chapter 1 (World) (v0.2) (Demo) (Aftermarket) (Unl).gb" size 2097152 crc 3f34ff66 sha1 a0bff49b6917186d27dc24773da0674a18a6212c ) +) + game ( name "Gluecksrad (Germany)" description "Gluecksrad (Germany)" @@ -24671,9 +25507,9 @@ game ( ) game ( - name "Gorf the Ghost Saves Halloween (World) (Aftermarket) (Homebrew)" - description "Gorf the Ghost Saves Halloween (World) (Aftermarket) (Homebrew)" - rom ( name "Gorf the Ghost Saves Halloween (World) (Aftermarket) (Homebrew).gb" size 262144 crc ab10cec6 sha1 9dcaa6824fab806683737bdf1c76609c68c451a5 ) + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Imagineer)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Imagineer)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Imagineer).gb" size 1048576 crc 5d43a385 sha1 d367f2dab5eacb10e785a13a2550ca7cc3e54177 ) ) game ( @@ -24683,9 +25519,9 @@ game ( ) game ( - name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Imagineer)" - description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Imagineer)" - rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Joushiki no Sho (Japan) (Imagineer).gb" size 1048576 crc 5d43a385 sha1 d367f2dab5eacb10e785a13a2550ca7cc3e54177 ) + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (IE Institute)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (IE Institute)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (IE Institute).gb" size 1048576 crc 180d54a7 sha1 7dce0adcbac61f0caae33646847fd06ced8c8b67 ) ) game ( @@ -24695,9 +25531,9 @@ game ( ) game ( - name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (IE Institute)" - description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (IE Institute)" - rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Kanji no Tatsujin (Japan) (IE Institute).gb" size 1048576 crc 180d54a7 sha1 7dce0adcbac61f0caae33646847fd06ced8c8b67 ) + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan) (Imagineer)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan) (Imagineer)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan) (Imagineer).gb" size 1048576 crc 71acbb67 sha1 e2ac91493248869aba6b7d26a36e5ff6bd6d6f5a flags verified ) ) game ( @@ -24707,9 +25543,9 @@ game ( ) game ( - name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan) (Imagineer)" - description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan) (Imagineer)" - rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Keisan no Tatsujin (Japan) (Imagineer).gb" size 1048576 crc 71acbb67 sha1 e2ac91493248869aba6b7d26a36e5ff6bd6d6f5a flags verified ) + name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Proto) (IE Institute)" + description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Proto) (IE Institute)" + rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Proto) (IE Institute).gb" size 1048576 crc 91ab959f sha1 2e1797646b2d3aa6fc9b2f5eaa248751133a0518 ) ) game ( @@ -24718,12 +25554,6 @@ game ( rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Imagineer).gb" size 1048576 crc 3c907f2c sha1 fa7a40acd835676fbcae9507a8aaaf1191f9b1cd ) ) -game ( - name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Proto) (IE Institute)" - description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Proto) (IE Institute)" - rom ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Nanmon no Sho (Japan) (Proto) (IE Institute).gb" size 1048576 crc 91ab959f sha1 2e1797646b2d3aa6fc9b2f5eaa248751133a0518 ) -) - game ( name "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Zukei no Tatsujin (Japan)" description "Goukaku Boy GOLD - Shikakui Atama o Maruku Suru - Zukei no Tatsujin (Japan)" @@ -24791,15 +25621,15 @@ game ( ) game ( - name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan) (IE Institute)" - description "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan) (IE Institute)" - rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan) (IE Institute).gb" size 262144 crc 5855b281 sha1 25f69cc4da819f7d5c449f6ad0cf4963011dc5a7 ) + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan) (Possible Proto) (IE Institute)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan) (Possible Proto) (IE Institute)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eijukugo 350 (Japan) (Possible Proto) (IE Institute).gb" size 262144 crc 5855b281 sha1 25f69cc4da819f7d5c449f6ad0cf4963011dc5a7 ) ) game ( - name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan) (IE Institute)" - description "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan) (IE Institute)" - rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan) (IE Institute).gb" size 262144 crc bc14fce6 sha1 48775723113ac0e3d1cbcf7381ba876d6dc30a7c ) + name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan) (Possible Proto) (IE Institute)" + description "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan) (Possible Proto) (IE Institute)" + rom ( name "Goukaku Boy Series - Koukou Nyuushi Derujun - Chuugaku Eitango 1700 (Japan) (Possible Proto) (IE Institute).gb" size 262144 crc bc14fce6 sha1 48775723113ac0e3d1cbcf7381ba876d6dc30a7c ) ) game ( @@ -24959,21 +25789,21 @@ game ( ) game ( - name "Gun Law (World) (Aftermarket) (Homebrew)" - description "Gun Law (World) (Aftermarket) (Homebrew)" - rom ( name "Gun Law (World) (Aftermarket) (Homebrew).gb" size 262144 crc b0d53211 sha1 ef6e3d287e99bd61861a333165c92b306238a45f ) + name "Gun Law (World) (Aftermarket) (Unl)" + description "Gun Law (World) (Aftermarket) (Unl)" + rom ( name "Gun Law (World) (Aftermarket) (Unl).gb" size 262144 crc b0d53211 sha1 ef6e3d287e99bd61861a333165c92b306238a45f ) ) game ( - name "Gunman Clive (World) (Aftermarket) (Homebrew)" - description "Gunman Clive (World) (Aftermarket) (Homebrew)" - rom ( name "Gunman Clive (World) (Aftermarket) (Homebrew).gb" size 65536 crc 11f5fded sha1 ec03763db2c0d754e2eb7e98384ed92fc8aeeb1d ) + name "Gunman Clive (World) (Demo) (Aftermarket) (Unl)" + description "Gunman Clive (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Gunman Clive (World) (Demo) (Aftermarket) (Unl).gb" size 65536 crc 11f5fded sha1 ec03763db2c0d754e2eb7e98384ed92fc8aeeb1d ) ) game ( - name "Gunship (USA) (Aftermarket) (Homebrew)" - description "Gunship (USA) (Aftermarket) (Homebrew)" - rom ( name "Gunship (USA) (Aftermarket) (Homebrew).gb" size 131072 crc bd31eef8 sha1 a801977c3746799cfb4d8bdfd679e45cccd3b719 ) + name "Gunship (World) (Aftermarket) (Unl)" + description "Gunship (World) (Aftermarket) (Unl)" + rom ( name "Gunship (World) (Aftermarket) (Unl).gb" size 131072 crc bd31eef8 sha1 a801977c3746799cfb4d8bdfd679e45cccd3b719 ) ) game ( @@ -25000,6 +25830,12 @@ game ( rom ( name "Hammerin' Harry - Ghost Building Company (USA) (Proto).gb" size 262144 crc 6c4d0377 sha1 c5f73b09f001fc4d7eaa40ffee00234ca6a41a41 ) ) +game ( + name "Harbour Attack (World) (Aftermarket) (Unl)" + description "Harbour Attack (World) (Aftermarket) (Unl)" + rom ( name "Harbour Attack (World) (Aftermarket) (Unl).gb" size 262144 crc 4018ebf7 sha1 5bbbe727ebc6a489f1a498d067e4f05d0d69b60f ) +) + game ( name "Harvest Moon GB (USA) (SGB Enhanced)" description "Harvest Moon GB (USA) (SGB Enhanced)" @@ -25012,12 +25848,6 @@ game ( rom ( name "Hatris (Japan, USA) (En).gb" size 65536 crc 7635f28b sha1 e8002f226e90ed52e1675c003d3c8ce804b56b0e ) ) -game ( - name "Hauntsfield (World) (Aftermarket) (Homebrew)" - description "Hauntsfield (World) (Aftermarket) (Homebrew)" - rom ( name "Hauntsfield (World) (Aftermarket) (Homebrew).gb" size 1048576 crc 287afc75 sha1 42ccc76883c041bc5c6c25a2e61ccc939c14811f ) -) - game ( name "Hayaoshi Quiz - Ouza Ketteisen (Japan) (SGB Enhanced)" description "Hayaoshi Quiz - Ouza Ketteisen (Japan) (SGB Enhanced)" @@ -25031,9 +25861,9 @@ game ( ) game ( - name "Heart Knight (World) (v1.0) (Aftermarket) (Homebrew)" - description "Heart Knight (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Heart Knight (World) (v1.0) (Aftermarket) (Homebrew).gb" size 32768 crc c7ecac73 sha1 dedcab41f58c58834e3534e877c494669a0d8952 ) + name "Heart Knight (World) (Aftermarket) (Unl)" + description "Heart Knight (World) (Aftermarket) (Unl)" + rom ( name "Heart Knight (World) (Aftermarket) (Unl).gb" size 32768 crc c7ecac73 sha1 dedcab41f58c58834e3534e877c494669a0d8952 ) ) game ( @@ -25078,6 +25908,12 @@ game ( rom ( name "Hercules (USA, Europe) (SGB Enhanced).gb" size 524288 crc 00a9001e sha1 215cceaccd4a33a2da6205f33a2803ff4004e2b1 flags verified ) ) +game ( + name "Hermano (World) (v1.1) (Aftermarket) (Unl)" + description "Hermano (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Hermano (World) (v1.1) (Aftermarket) (Unl).gb" size 262144 crc 74a0419b sha1 c42cfe91a1ec593a76291e031c47137bd794ffda ) +) + game ( name "Hero Shuugou!! Pinball Party (Japan)" description "Hero Shuugou!! Pinball Party (Japan)" @@ -25205,9 +26041,9 @@ game ( ) game ( - name "Hook (Europe) (Beta)" - description "Hook (Europe) (Beta)" - rom ( name "Hook (Europe) (Beta).gb" size 131072 crc c091abc8 sha1 0299d84e5f722e9298c1ce190b8e4a785849b868 ) + name "Hook (USA) (Sample)" + description "Hook (USA) (Sample)" + rom ( name "Hook (USA) (Sample).gb" size 131072 crc c091abc8 sha1 0299d84e5f722e9298c1ce190b8e4a785849b868 ) ) game ( @@ -25246,6 +26082,12 @@ game ( rom ( name "Hudson Hawk (Europe) (Proto).gb" size 131072 crc d4cd525d sha1 07c6a49f7c340d3cc78ca688eb1591853255a6c6 ) ) +game ( + name "Hugo (World) (Aftermarket) (Unl)" + description "Hugo (World) (Aftermarket) (Unl)" + rom ( name "Hugo (World) (Aftermarket) (Unl).gb" size 262144 crc 8cc87f60 sha1 53fac2774b29a32501788e1eac65db23bf5c7b8f ) +) + game ( name "Hugo (Europe) (SGB Enhanced)" description "Hugo (Europe) (SGB Enhanced)" @@ -25270,6 +26112,12 @@ game ( rom ( name "Humans, The (USA).gb" size 262144 crc 1df2e81d sha1 39b7f8f6abb213bb5727379b864106ca2947fe6f ) ) +game ( + name "Humans, The (USA) (QUByte Classics)" + description "Humans, The (USA) (QUByte Classics)" + rom ( name "Humans, The (USA) (QUByte Classics).gb" size 262144 crc 4580ec88 sha1 669f4645b426400a4853793c7070c53642f71556 ) +) + game ( name "Hunchback of Notre Dame, The - 5 Foolishly Fun Topsy Turvy Games (USA, Europe) (SGB Enhanced)" description "Hunchback of Notre Dame, The - 5 Foolishly Fun Topsy Turvy Games (USA, Europe) (SGB Enhanced)" @@ -25313,9 +26161,9 @@ game ( ) game ( - name "If (World) (Aftermarket) (Homebrew)" - description "If (World) (Aftermarket) (Homebrew)" - rom ( name "If (World) (Aftermarket) (Homebrew).gb" size 1048576 crc be7e4454 sha1 c11d8dc9ce96133f679678b07822a82f985e16f9 ) + name "If (World) (Aftermarket) (Unl)" + description "If (World) (Aftermarket) (Unl)" + rom ( name "If (World) (Aftermarket) (Unl).gb" size 1048576 crc be7e4454 sha1 c11d8dc9ce96133f679678b07822a82f985e16f9 ) ) game ( @@ -25330,10 +26178,16 @@ game ( rom ( name "Ikari no Yousai 2 (Japan).gb" size 131072 crc 6d4fd9aa sha1 ae437d4fb39d7438fc9eb98c91820aa2b5161b4f ) ) +game ( + name "Impossible Gameboy (World) (Aftermarket) (Unl)" + description "Impossible Gameboy (World) (Aftermarket) (Unl)" + rom ( name "Impossible Gameboy (World) (Aftermarket) (Unl).gb" size 131072 crc ab65b738 sha1 d31cedd6227b23cf3d8ef81c73f133ab0b57e4f4 ) +) + game ( name "In Your Face (USA)" description "In Your Face (USA)" - rom ( name "In Your Face (USA).gb" size 131072 crc 80ac487e sha1 0be0f2a952497b321655dbee5c89678f40bf0b5a ) + rom ( name "In Your Face (USA).gb" size 131072 crc 80ac487e sha1 0be0f2a952497b321655dbee5c89678f40bf0b5a flags verified ) ) game ( @@ -25363,7 +26217,7 @@ game ( game ( name "InfoGenius Productivity Pak - Berlitz French Translator (USA, Europe)" description "InfoGenius Productivity Pak - Berlitz French Translator (USA, Europe)" - rom ( name "InfoGenius Productivity Pak - Berlitz French Translator (USA, Europe).gb" size 131072 crc 80485fda sha1 ea77a00e9982ffa710ce9e179d4614419f9e1a35 ) + rom ( name "InfoGenius Productivity Pak - Berlitz French Translator (USA, Europe).gb" size 131072 crc 80485fda sha1 ea77a00e9982ffa710ce9e179d4614419f9e1a35 flags verified ) ) game ( @@ -25414,12 +26268,24 @@ game ( rom ( name "Initial D Gaiden (Japan) (SGB Enhanced).gb" size 262144 crc 6cc56612 sha1 1b3c4c1c4dfca46a009eb2e5cd45b343d7ee6681 ) ) +game ( + name "Interblocked (World) (Aftermarket) (Unl)" + description "Interblocked (World) (Aftermarket) (Unl)" + rom ( name "Interblocked (World) (Aftermarket) (Unl).gb" size 262144 crc 5c208855 sha1 8e46486533a3de9ee87cc07bf8efaf818752a61a ) +) + game ( name "International Superstar Soccer (USA, Europe) (SGB Enhanced)" description "International Superstar Soccer (USA, Europe) (SGB Enhanced)" rom ( name "International Superstar Soccer (USA, Europe) (SGB Enhanced).gb" size 262144 crc 94757be8 sha1 13f2fc0945fb7a90f4d87d8c4e310dec9af6b792 ) ) +game ( + name "Into the Blue (World) (Aftermarket) (Unl)" + description "Into the Blue (World) (Aftermarket) (Unl)" + rom ( name "Into the Blue (World) (Aftermarket) (Unl).gb" size 131072 crc 7714e96e sha1 5ac7a349bb37c8767c9db264ed8ae7b7647fa8ea ) +) + game ( name "Ippatsu Gyakuten! DX Bakenou (Japan)" description "Ippatsu Gyakuten! DX Bakenou (Japan)" @@ -25481,9 +26347,9 @@ game ( ) game ( - name "Jabberwocky (World) (Aftermarket) (Homebrew)" - description "Jabberwocky (World) (Aftermarket) (Homebrew)" - rom ( name "Jabberwocky (World) (Aftermarket) (Homebrew).gb" size 1048576 crc cfc51717 sha1 b4e447f2197688c740a45dce27879a62c742fb96 ) + name "Jabberwocky (World) (Aftermarket) (Unl)" + description "Jabberwocky (World) (Aftermarket) (Unl)" + rom ( name "Jabberwocky (World) (Aftermarket) (Unl).gb" size 1048576 crc cfc51717 sha1 b4e447f2197688c740a45dce27879a62c742fb96 ) ) game ( @@ -25511,9 +26377,9 @@ game ( ) game ( - name "Jana of the Jungle (World) (Demo) (Aftermarket) (Homebrew)" - description "Jana of the Jungle (World) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Jana of the Jungle (World) (Demo) (Aftermarket) (Homebrew).gb" size 262144 crc c68e751a sha1 dfc65dcf700a26b273d705b7cfececbc44b80587 ) + name "Jane in the Jungle (World) (Aftermarket) (Unl)" + description "Jane in the Jungle (World) (Aftermarket) (Unl)" + rom ( name "Jane in the Jungle (World) (Aftermarket) (Unl).gb" size 262144 crc c68e751a sha1 dfc65dcf700a26b273d705b7cfececbc44b80587 ) ) game ( @@ -25543,7 +26409,7 @@ game ( game ( name "Jeep Jamboree - Off-Road Adventure (USA)" description "Jeep Jamboree - Off-Road Adventure (USA)" - rom ( name "Jeep Jamboree - Off-Road Adventure (USA).gb" size 131072 crc a1e76a33 sha1 988a40823f7db661bc91ffff8fc1bcd80e64f18d ) + rom ( name "Jeep Jamboree - Off-Road Adventure (USA).gb" size 131072 crc a1e76a33 sha1 988a40823f7db661bc91ffff8fc1bcd80e64f18d flags verified ) ) game ( @@ -25601,15 +26467,9 @@ game ( ) game ( - name "Jetsons, The - Robot Panic (USA) (Rev 1) (Possible Proto)" - description "Jetsons, The - Robot Panic (USA) (Rev 1) (Possible Proto)" - rom ( name "Jetsons, The - Robot Panic (USA) (Rev 1) (Possible Proto).gb" size 131072 crc cc38cf0d sha1 38b5ec2c74316696b7731cd88e56be4519084168 ) -) - -game ( - name "Jetsons, The - Robot Panic (Japan) (Proto)" - description "Jetsons, The - Robot Panic (Japan) (Proto)" - rom ( name "Jetsons, The - Robot Panic (Japan) (Proto).gb" size 131072 crc d016d141 sha1 6035ee9364413b9eac7eb2290a806ffb57dc25cc ) + name "Jet Set Willy (World) (Aftermarket) (Unl)" + description "Jet Set Willy (World) (Aftermarket) (Unl)" + rom ( name "Jet Set Willy (World) (Aftermarket) (Unl).gb" size 262144 crc 1686d7ed sha1 0e594224506fd087e36c66bb66905d4c91b02461 ) ) game ( @@ -25618,6 +26478,18 @@ game ( rom ( name "Jetsons, The - Robot Panic (USA, Europe).gb" size 131072 crc 6386c870 sha1 1790c7462907f803e9641a330df6f06aa5e4e985 flags verified ) ) +game ( + name "Jetsons, The - Robot Panic (USA, Europe) (Rev 1)" + description "Jetsons, The - Robot Panic (USA, Europe) (Rev 1)" + rom ( name "Jetsons, The - Robot Panic (USA, Europe) (Rev 1).gb" size 131072 crc cc38cf0d sha1 38b5ec2c74316696b7731cd88e56be4519084168 ) +) + +game ( + name "Jetsons, The - Robot Panic (Japan) (Proto)" + description "Jetsons, The - Robot Panic (Japan) (Proto)" + rom ( name "Jetsons, The - Robot Panic (Japan) (Proto).gb" size 131072 crc d016d141 sha1 6035ee9364413b9eac7eb2290a806ffb57dc25cc ) +) + game ( name "Jikuu Senki Mu (Japan)" description "Jikuu Senki Mu (Japan)" @@ -25642,6 +26514,12 @@ game ( rom ( name "Jimmy Connors Tennis (USA, Europe) (Beta).gb" size 131072 crc eb50caf2 sha1 4ca04a3270e217d54d8c5fa7a254fdbcb48c5b87 ) ) +game ( + name "Jimmy Connors Tennis (USA, Europe) (1993-03-19) (Beta)" + description "Jimmy Connors Tennis (USA, Europe) (1993-03-19) (Beta)" + rom ( name "Jimmy Connors Tennis (USA, Europe) (1993-03-19) (Beta).gb" size 65536 crc 4ee3e02e sha1 06c9018f7943362f8b9571486b6412de11672718 ) +) + game ( name "Jinsei Game (Japan) (SGB Enhanced)" description "Jinsei Game (Japan) (SGB Enhanced)" @@ -25672,6 +26550,12 @@ game ( rom ( name "Joe & Mac - Caveman Ninja (Europe) (En,Fr,De,Es,It,Nl,Sv) (Beta).gb" size 262144 crc 381c62ee sha1 979e36765291153b82025b1f036c08fe9c23cfa5 ) ) +game ( + name "Joe Blade 2 (World) (Aftermarket) (Unl)" + description "Joe Blade 2 (World) (Aftermarket) (Unl)" + rom ( name "Joe Blade 2 (World) (Aftermarket) (Unl).gb" size 524288 crc 09f75c70 sha1 f001dffcd16be670c36a98dd9136f6f9fbf5b85d ) +) + game ( name "John Madden Football (USA) (Proto 2) (SGB Enhanced)" description "John Madden Football (USA) (Proto 2) (SGB Enhanced)" @@ -25801,7 +26685,7 @@ game ( game ( name "Kaisen Game - Navyblue (Japan)" description "Kaisen Game - Navyblue (Japan)" - rom ( name "Kaisen Game - Navyblue (Japan).gb" size 65536 crc afd8c47c sha1 7fbf13dd0b5a4e7798724270a81006be9950f81a ) + rom ( name "Kaisen Game - Navyblue (Japan).gb" size 65536 crc afd8c47c sha1 7fbf13dd0b5a4e7798724270a81006be9950f81a flags verified ) ) game ( @@ -25889,9 +26773,9 @@ game ( ) game ( - name "Kenzie's Birthday Dash (World) (Aftermarket) (Homebrew)" - description "Kenzie's Birthday Dash (World) (Aftermarket) (Homebrew)" - rom ( name "Kenzie's Birthday Dash (World) (Aftermarket) (Homebrew).gb" size 1048576 crc 986bfd75 sha1 6d15b5bc33d7c7771ba62d56ae7f25fa081bc564 ) + name "Kenzie's Birthday Dash (World) (Aftermarket) (Unl)" + description "Kenzie's Birthday Dash (World) (Aftermarket) (Unl)" + rom ( name "Kenzie's Birthday Dash (World) (Aftermarket) (Unl).gb" size 1048576 crc 986bfd75 sha1 6d15b5bc33d7c7771ba62d56ae7f25fa081bc564 ) ) game ( @@ -26005,19 +26889,19 @@ game ( game ( name "Kirby no Block Ball (Japan) (SGB Enhanced)" description "Kirby no Block Ball (Japan) (SGB Enhanced)" - rom ( name "Kirby no Block Ball (Japan) (SGB Enhanced).gb" size 524288 crc df3bbcd7 sha1 3fecc964d2c13ad98abac1df49f05c488833ef5a ) + rom ( name "Kirby no Block Ball (Japan) (SGB Enhanced).gb" size 524288 crc df3bbcd7 sha1 3fecc964d2c13ad98abac1df49f05c488833ef5a flags verified ) ) game ( name "Kirby no Kirakira Kids (Japan) (SGB Enhanced)" description "Kirby no Kirakira Kids (Japan) (SGB Enhanced)" - rom ( name "Kirby no Kirakira Kids (Japan) (SGB Enhanced).gb" size 262144 crc 47f42f42 sha1 2c46c42be76eca134e188814345afa390e298811 ) + rom ( name "Kirby no Kirakira Kids (Japan) (SGB Enhanced).gb" size 262144 crc 47f42f42 sha1 2c46c42be76eca134e188814345afa390e298811 flags verified ) ) game ( name "Kirby no Pinball (Japan)" description "Kirby no Pinball (Japan)" - rom ( name "Kirby no Pinball (Japan).gb" size 262144 crc 8b44fb7d sha1 678ca586f5a2e2fc894fb8e9f7b9efa54fabba44 ) + rom ( name "Kirby no Pinball (Japan).gb" size 262144 crc 8b44fb7d sha1 678ca586f5a2e2fc894fb8e9f7b9efa54fabba44 flags verified ) ) game ( @@ -26194,6 +27078,12 @@ game ( rom ( name "Krusty's Fun House (USA, Europe).gb" size 131072 crc 1cedb141 sha1 e61039c52c053a8ae1bdfffa3f694934569bb570 flags verified ) ) +game ( + name "Kudzu (World) (v0.96) (Demo) (Aftermarket) (Unl)" + description "Kudzu (World) (v0.96) (Demo) (Aftermarket) (Unl)" + rom ( name "Kudzu (World) (v0.96) (Demo) (Aftermarket) (Unl).gb" size 2097152 crc 0610049a sha1 a6fbe1a524547bebabc5e6b3baff1dff8f13dbd0 ) +) + game ( name "Kuma no Puutarou - Takara Sagashi da Ooiri Game Battle! (Japan) (SGB Enhanced)" description "Kuma no Puutarou - Takara Sagashi da Ooiri Game Battle! (Japan) (SGB Enhanced)" @@ -26206,6 +27096,12 @@ game ( rom ( name "Kung-Fu Master (USA, Europe).gb" size 65536 crc 3340e600 sha1 b0bb485e2b57793da9f153db074c13a060a1e0d4 flags verified ) ) +game ( + name "Kung-Fu Master (USA, Europe) (Beta)" + description "Kung-Fu Master (USA, Europe) (Beta)" + rom ( name "Kung-Fu Master (USA, Europe) (Beta).gb" size 65536 crc e0c33c1a sha1 1ce6301d56294b71068514c666ad2157551134e7 ) +) + game ( name "Kuusou Kagaku Sekai Gulliver Boy - Kuusou Kagaku Puzzle Purittopon!! (Japan) (SGB Enhanced)" description "Kuusou Kagaku Sekai Gulliver Boy - Kuusou Kagaku Puzzle Purittopon!! (Japan) (SGB Enhanced)" @@ -26243,9 +27139,9 @@ game ( ) game ( - name "Laser Squad Alter (World) (Aftermarket) (Homebrew)" - description "Laser Squad Alter (World) (Aftermarket) (Homebrew)" - rom ( name "Laser Squad Alter (World) (Aftermarket) (Homebrew).gb" size 1048576 crc a39b3a5a sha1 1620e585e77a2457cffde82453bec0c7a04e07cf ) + name "Laser Squad Alter (World) (Aftermarket) (Unl)" + description "Laser Squad Alter (World) (Aftermarket) (Unl)" + rom ( name "Laser Squad Alter (World) (Aftermarket) (Unl).gb" size 1048576 crc a39b3a5a sha1 1620e585e77a2457cffde82453bec0c7a04e07cf ) ) game ( @@ -26255,9 +27151,21 @@ game ( ) game ( - name "Lawn Mower Land (World) (Aftermarket) (Homebrew)" - description "Lawn Mower Land (World) (Aftermarket) (Homebrew)" - rom ( name "Lawn Mower Land (World) (Aftermarket) (Homebrew).gb" size 32768 crc 11c62e39 sha1 1d6aa817ebf2a7e5d22285b906540272b67169da ) + name "Last Crown Warriors (World) (Demo) (SGB Enhanced) (Aftermarket) (Unl)" + description "Last Crown Warriors (World) (Demo) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Last Crown Warriors (World) (Demo) (SGB Enhanced) (Aftermarket) (Unl).gb" size 262144 crc 2c430576 sha1 0e290b387a45b6ea85c6d49bf18bce3ce94951b7 ) +) + +game ( + name "Last Crown Warriors (World) (v1.1.1) (Demo) (SGB Enhanced) (Aftermarket) (Unl)" + description "Last Crown Warriors (World) (v1.1.1) (Demo) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Last Crown Warriors (World) (v1.1.1) (Demo) (SGB Enhanced) (Aftermarket) (Unl).gb" size 262144 crc 5cf1a6f9 sha1 9fac1324e863f719674219eb41e45f1f745c67a9 ) +) + +game ( + name "Lawn Mower Land (World) (Aftermarket) (Unl)" + description "Lawn Mower Land (World) (Aftermarket) (Unl)" + rom ( name "Lawn Mower Land (World) (Aftermarket) (Unl).gb" size 32768 crc 11c62e39 sha1 1d6aa817ebf2a7e5d22285b906540272b67169da ) ) game ( @@ -26284,6 +27192,12 @@ game ( rom ( name "Lazlos' Leap (USA).gb" size 65536 crc 31fb404b sha1 c111470fcdadf191cf843e50c8f3d3dbb995a5c5 ) ) +game ( + name "Leak, The (World) (Aftermarket) (Unl)" + description "Leak, The (World) (Aftermarket) (Unl)" + rom ( name "Leak, The (World) (Aftermarket) (Unl).GB" size 65536 crc ba3cfeae sha1 98de2d8be75e6d9cb4e87afe14b1380c033de797 ) +) + game ( name "Learn and Play - Blackjack & Solitaire (USA) (1994-08-09) (Proto)" description "Learn and Play - Blackjack & Solitaire (USA) (1994-08-09) (Proto)" @@ -26351,9 +27265,21 @@ game ( ) game ( - name "Legend of Zelda, The - Link's Awakening DX (Germany) (Proto) (1998-11-16)" - description "Legend of Zelda, The - Link's Awakening DX (Germany) (Proto) (1998-11-16)" - rom ( name "Legend of Zelda, The - Link's Awakening DX (Germany) (Proto) (1998-11-16).gb" size 524288 crc f7c59f5c sha1 d1a10a3f129bf060f16d1fb5f991ef6e2f28b97c ) + name "Legend of Zelda, The - Link's Awakening DX (France) (Proto) (1998-11-17)" + description "Legend of Zelda, The - Link's Awakening DX (France) (Proto) (1998-11-17)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (France) (Proto) (1998-11-17).gb" size 524288 crc bfa800c0 sha1 3d48bcec56bf202d3362ba3e5e20233f996492c5 ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Proto) (1998-11-08)" + description "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Proto) (1998-11-08)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Proto) (1998-11-08).gb" size 524288 crc d8ba6631 sha1 9d6da903a5481aadfb20d75954bd01917497a38d ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (Germany) (Proto) (1998-11-17)" + description "Legend of Zelda, The - Link's Awakening DX (Germany) (Proto) (1998-11-17)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (Germany) (Proto) (1998-11-17).gb" size 524288 crc f7c59f5c sha1 d1a10a3f129bf060f16d1fb5f991ef6e2f28b97c ) ) game ( @@ -26389,7 +27315,7 @@ game ( game ( name "Lemmings 2 - The Tribes (Europe)" description "Lemmings 2 - The Tribes (Europe)" - rom ( name "Lemmings 2 - The Tribes (Europe).gb" size 524288 crc 9800bd49 sha1 76ccf9ac82faebc7f9c4a4c8b5cd47ddea46c486 ) + rom ( name "Lemmings 2 - The Tribes (Europe).gb" size 524288 crc 9800bd49 sha1 76ccf9ac82faebc7f9c4a4c8b5cd47ddea46c486 flags verified ) ) game ( @@ -26404,6 +27330,18 @@ game ( rom ( name "Lethal Weapon (USA, Europe) (Beta).gb" size 131072 crc d585ab23 sha1 2221ba322acffc9d7ae5400752e16d0455fda3ef ) ) +game ( + name "Life's Too Short (World) (Aftermarket) (Unl)" + description "Life's Too Short (World) (Aftermarket) (Unl)" + rom ( name "Life's Too Short (World) (Aftermarket) (Unl).gb" size 262144 crc 458174cc sha1 7b704cd999cbeeb9991d675e2b1e67a906fa766d ) +) + +game ( + name "Linea, La (World) (Aftermarket) (Unl)" + description "Linea, La (World) (Aftermarket) (Unl)" + rom ( name "Linea, La (World) (Aftermarket) (Unl).gb" size 262144 crc c8750c01 sha1 00348fec54b5d3ebb762484bdcc015881bb9e95b ) +) + game ( name "Lingo (Europe) (En,Fr,De,Nl)" description "Lingo (Europe) (En,Fr,De,Nl)" @@ -26464,6 +27402,54 @@ game ( rom ( name "Little Mermaid, The (Spain) (Proto).gb" size 131072 crc d19cf413 sha1 463036660b2739e450a7bdea68772c6738e04a53 ) ) +game ( + name "Little Tales of Alexandria, The (World) (MBC3) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The (World) (MBC3) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The (World) (MBC3) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl).gb" size 524288 crc 9c4f03fd sha1 288cb53b4782df4409ee683e9aa11b4dd2a3a53e ) +) + +game ( + name "Little Tales of Alexandria, The (World) (MBC3) (SGB Enhanced) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The (World) (MBC3) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The (World) (MBC3) (SGB Enhanced) (Aftermarket) (Unl).gb" size 524288 crc e5988949 sha1 08d033c7ef20fd4d24d1f07b3ebb177fb9b78673 ) +) + +game ( + name "Little Tales of Alexandria, The (World) (MBC5) (SGB Enhanced) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The (World) (MBC5) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The (World) (MBC5) (SGB Enhanced) (Aftermarket) (Unl).gb" size 524288 crc 59568248 sha1 6571db155f6f25eeeec86d28b105bf8fef156322 ) +) + +game ( + name "Little Tales of Alexandria, The (World) (MBC5) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The (World) (MBC5) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The (World) (MBC5) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl).gb" size 524288 crc a26345b8 sha1 641110cb187657fd15ea254440e1c74ab4a88856 ) +) + +game ( + name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC3) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC3) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC3) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl).gb" size 131072 crc d70f1d25 sha1 02e2fb6cbc5cff05ed775c9e1cd9acc07fa2e036 ) +) + +game ( + name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC5) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC5) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC5) (SGB Enhanced) (Batteryless) (Aftermarket) (Unl).gb" size 131072 crc ae07c093 sha1 9f40b8719b3fdd2f7e6c59a4f616e9eb712d538d ) +) + +game ( + name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC3) (SGB Enhanced) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC3) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC3) (SGB Enhanced) (Aftermarket) (Unl).gb" size 131072 crc 34671dc6 sha1 377d22d54e6e1fa4fcd4b4576d5886774f9f6c97 ) +) + +game ( + name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC5) (SGB Enhanced) (Aftermarket) (Unl)" + description "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC5) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Little Tales of Alexandria, The - Mr Meows Dance Party! (World) (MBC5) (SGB Enhanced) (Aftermarket) (Unl).gb" size 131072 crc a8fb0d7a sha1 26803ba3413c7c52a8a58393f63472bc87ec3c6b ) +) + game ( name "Lock n' Chase ~ Lock 'n' Chase (World)" description "Lock n' Chase ~ Lock 'n' Chase (World)" @@ -26543,9 +27529,9 @@ game ( ) game ( - name "Lucy and the Gem Dungeon (World) (Aftermarket) (Homebrew)" - description "Lucy and the Gem Dungeon (World) (Aftermarket) (Homebrew)" - rom ( name "Lucy and the Gem Dungeon (World) (Aftermarket) (Homebrew).gb" size 524288 crc 1a5106a2 sha1 f56c1b324b8c1e17da86e40c5e9a887ec19b0c80 ) + name "Lucy and the Gem Dungeon (World) (Aftermarket) (Unl)" + description "Lucy and the Gem Dungeon (World) (Aftermarket) (Unl)" + rom ( name "Lucy and the Gem Dungeon (World) (Aftermarket) (Unl).gb" size 524288 crc 1a5106a2 sha1 f56c1b324b8c1e17da86e40c5e9a887ec19b0c80 ) ) game ( @@ -26572,6 +27558,18 @@ game ( rom ( name "Mach Go Go Go (Japan) (SGB Enhanced).gb" size 262144 crc 016d230b sha1 baea8b49ce2402c5c094ddae0320a382c0d95d86 ) ) +game ( + name "Machine, The (World) (Aftermarket) (Unl)" + description "Machine, The (World) (Aftermarket) (Unl)" + rom ( name "Machine, The (World) (Aftermarket) (Unl).gb" size 2097152 crc b06036a9 sha1 50c5d1eb7c8946ac2d7e2c566b1ea4a9b0d58e90 ) +) + +game ( + name "Mad Monster (World) (Aftermarket) (Unl)" + description "Mad Monster (World) (Aftermarket) (Unl)" + rom ( name "Mad Monster (World) (Aftermarket) (Unl).gb" size 524288 crc c3fd371c sha1 9f4bea7ca7d26080110f54392314c60761236638 ) +) + game ( name "Madden 95 (USA, Europe) (SGB Enhanced)" description "Madden 95 (USA, Europe) (SGB Enhanced)" @@ -26621,9 +27619,15 @@ game ( ) game ( - name "Magipanels (World) (Rev 1) (Demo) (Aftermarket) (Homebrew)" - description "Magipanels (World) (Rev 1) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Magipanels (World) (Rev 1) (Demo) (Aftermarket) (Homebrew).gb" size 131072 crc 76fcbc30 sha1 7a759372bd013dcdb59c9131a2908085fc04d648 ) + name "Magipanels (World) (2022-02-09) (Demo) (Aftermarket) (Unl)" + description "Magipanels (World) (2022-02-09) (Demo) (Aftermarket) (Unl)" + rom ( name "Magipanels (World) (2022-02-09) (Demo) (Aftermarket) (Unl).gb" size 131072 crc 76fcbc30 sha1 7a759372bd013dcdb59c9131a2908085fc04d648 ) +) + +game ( + name "Magipanels (World) (Aftermarket) (Unl)" + description "Magipanels (World) (Aftermarket) (Unl)" + rom ( name "Magipanels (World) (Aftermarket) (Unl).gb" size 131072 crc 0b66561b sha1 c9513f6769098f2185f632f87386788f0f0b6ad8 ) ) game ( @@ -26663,9 +27667,9 @@ game ( ) game ( - name "Make Way (World) (Aftermarket) (Homebrew)" - description "Make Way (World) (Aftermarket) (Homebrew)" - rom ( name "Make Way (World) (Aftermarket) (Homebrew).gb" size 1048576 crc edeee5a8 sha1 19fd02e9318ed81ec968a2fca31ea0c3d8d94a7b ) + name "Make Way (World) (Aftermarket) (Unl)" + description "Make Way (World) (Aftermarket) (Unl)" + rom ( name "Make Way (World) (Aftermarket) (Unl).gb" size 1048576 crc edeee5a8 sha1 19fd02e9318ed81ec968a2fca31ea0c3d8d94a7b ) ) game ( @@ -26735,15 +27739,27 @@ game ( ) game ( - name "Marron Helps a Friend (World) (Aftermarket) (Homebrew)" - description "Marron Helps a Friend (World) (Aftermarket) (Homebrew)" - rom ( name "Marron Helps a Friend (World) (Aftermarket) (Homebrew).gb" size 1048576 crc 08a3a987 sha1 adcd56fa3eba93edd20be25ae5cb349070cd0323 ) + name "Marron Helps a Friend (World) (Aftermarket) (Unl)" + description "Marron Helps a Friend (World) (Aftermarket) (Unl)" + rom ( name "Marron Helps a Friend (World) (Aftermarket) (Unl).gb" size 1048576 crc 08a3a987 sha1 adcd56fa3eba93edd20be25ae5cb349070cd0323 flags verified ) ) game ( name "Maru's Mission (USA)" description "Maru's Mission (USA)" - rom ( name "Maru's Mission (USA).gb" size 131072 crc 6e4f1eb3 sha1 91446b1cc6dbf3b98b81f13e35ffe7bfaaa027aa ) + rom ( name "Maru's Mission (USA).gb" size 131072 crc 6e4f1eb3 sha1 91446b1cc6dbf3b98b81f13e35ffe7bfaaa027aa flags verified ) +) + +game ( + name "Marzipan Beef Reverser (World) (v2.0) (Aftermarket) (Unl)" + description "Marzipan Beef Reverser (World) (v2.0) (Aftermarket) (Unl)" + rom ( name "Marzipan Beef Reverser (World) (v2.0) (Aftermarket) (Unl).gb" size 262144 crc dccaeb60 sha1 1e4fc83bfe9c9063975a3862770e4afee3f947a4 ) +) + +game ( + name "Marzipan Beef Reverser (World) (Aftermarket) (Unl)" + description "Marzipan Beef Reverser (World) (Aftermarket) (Unl)" + rom ( name "Marzipan Beef Reverser (World) (Aftermarket) (Unl).gb" size 131072 crc 4c3e0d15 sha1 6cbfb0390ee555718b5b0c3a5437b7d3d4ee0008 ) ) game ( @@ -26902,6 +27918,12 @@ game ( rom ( name "Mega Man V (USA) (SGB Enhanced).gb" size 524288 crc 72e6d21d sha1 9a7da0e4d3f49e4a0b94e85cd64e28a687d81260 ) ) +game ( + name "Mega Memory (World) (Unl)" + description "Mega Memory (World) (Unl)" + rom ( name "Mega Memory (World) (Unl).gb" size 32768 crc dba81e98 sha1 7690ccaa54b71188d07cb546d3c4d42c1d6363a8 ) +) + game ( name "Megalit (Japan)" description "Megalit (Japan)" @@ -26938,12 +27960,6 @@ game ( rom ( name "Meitantei Conan - Giwaku no Gouka Ressha (Japan) (SGB Enhanced).gb" size 262144 crc 1dc5c31a sha1 125db863bad5d48033d0bf94ed808b2b8d34ca2f ) ) -game ( - name "Melanie and the Magic Forest (World) (Aftermarket) (Homebrew)" - description "Melanie and the Magic Forest (World) (Aftermarket) (Homebrew)" - rom ( name "Melanie and the Magic Forest (World) (Aftermarket) (Homebrew).gb" size 262144 crc f614bdff sha1 7e46c193f6566f620acf20ead3a1fca1d677c221 ) -) - game ( name "Mercenary Force (USA, Europe)" description "Mercenary Force (USA, Europe)" @@ -26962,6 +27978,12 @@ game ( rom ( name "Metal Masters (USA) (Beta).gb" size 131072 crc 3378064b sha1 572c820f7ec7a3c96df9af441da244befa5223b9 ) ) +game ( + name "Meteorite (World) (Aftermarket) (Unl)" + description "Meteorite (World) (Aftermarket) (Unl)" + rom ( name "Meteorite (World) (Aftermarket) (Unl).gb" size 262144 crc 50cf593d sha1 0e88a47faf3273f87c1ead7f789faeb06d5333f3 ) +) + game ( name "Metroid II - Return of Samus (World)" description "Metroid II - Return of Samus (World)" @@ -27079,19 +28101,7 @@ game ( game ( name "Midori no Makibaou (Japan) (SGB Enhanced)" description "Midori no Makibaou (Japan) (SGB Enhanced)" - rom ( name "Midori no Makibaou (Japan) (SGB Enhanced).gb" size 262144 crc 1dd93d95 sha1 4de380b202e375761f9fe7fb13349f5b02e2dac2 ) -) - -game ( - name "Midterm Moments (World) (Aftermarket) (Homebrew)" - description "Midterm Moments (World) (Aftermarket) (Homebrew)" - rom ( name "Midterm Moments (World) (Aftermarket) (Homebrew).gb" size 262144 crc f9a5ed4e sha1 8b3e18287d5adf3b5a711e28a896f843927f22a2 ) -) - -game ( - name "Mighty Morphin Power Rangers (USA, Europe) (Beta) (SGB Enhanced)" - description "Mighty Morphin Power Rangers (USA, Europe) (Beta) (SGB Enhanced)" - rom ( name "Mighty Morphin Power Rangers (USA, Europe) (Beta) (SGB Enhanced).gb" size 262144 crc caab9ac9 sha1 be42f45d8038ce28461ed36ba9164854632aebe0 ) + rom ( name "Midori no Makibaou (Japan) (SGB Enhanced).gb" size 262144 crc 1dd93d95 sha1 4de380b202e375761f9fe7fb13349f5b02e2dac2 flags verified ) ) game ( @@ -27100,6 +28110,12 @@ game ( rom ( name "Mighty Morphin Power Rangers (USA, Europe) (SGB Enhanced).gb" size 262144 crc c60d032a sha1 ef88476d9a1a26b67f3535ae7afcf5156578e38c flags verified ) ) +game ( + name "Mighty Morphin Power Rangers (USA, Europe) (Beta) (SGB Enhanced)" + description "Mighty Morphin Power Rangers (USA, Europe) (Beta) (SGB Enhanced)" + rom ( name "Mighty Morphin Power Rangers (USA, Europe) (Beta) (SGB Enhanced).gb" size 262144 crc caab9ac9 sha1 be42f45d8038ce28461ed36ba9164854632aebe0 ) +) + game ( name "Mighty Morphin Power Rangers - The Movie (USA, Europe) (SGB Enhanced)" description "Mighty Morphin Power Rangers - The Movie (USA, Europe) (SGB Enhanced)" @@ -27190,6 +28206,138 @@ game ( rom ( name "Mini-Putt (Japan).gb" size 65536 crc 33cd7550 sha1 e2a75fc09d8f9e56325449ca91cda9a68d058c1f ) ) +game ( + name "Minolta 2085 Adj. Program (USA) (Unl)" + description "Minolta 2085 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2085 Adj. Program (USA) (Unl).gb" size 32768 crc de660a82 sha1 d0e586988108b7238bebcac055cb7c6982abf81c ) +) + +game ( + name "Minolta 2097 Adj. Program (USA) (Unl)" + description "Minolta 2097 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2097 Adj. Program (USA) (Unl).gb" size 32768 crc 0a9ab6e7 sha1 68968d1b1fc84b2381159c0938675d2048c57ee2 flags verified ) +) + +game ( + name "Minolta 2098 Adj. Program (USA) (Unl)" + description "Minolta 2098 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2098 Adj. Program (USA) (Unl).gb" size 32768 crc 1b7eb836 sha1 dc0f429cc1eac8dd9009a9b30dab0803099be646 ) +) + +game ( + name "Minolta 2156 Adj. Program (USA) (Unl)" + description "Minolta 2156 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2156 Adj. Program (USA) (Unl).gb" size 32768 crc 3af37d46 sha1 c4b46446553bf6c25e3b3c1d5cd450a205ff6692 ) +) + +game ( + name "Minolta 2162 Adj. Program (USA) (Unl)" + description "Minolta 2162 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2162 Adj. Program (USA) (Unl).gb" size 32768 crc 54a6aec4 sha1 58202d2f8f823c52c09275df3fa63b4b2a630bdc ) +) + +game ( + name "Minolta 2162 Adj. Program (USA) (Unl) (Alt)" + description "Minolta 2162 Adj. Program (USA) (Unl) (Alt)" + rom ( name "Minolta 2162 Adj. Program (USA) (Unl) (Alt).gb" size 32768 crc 74ecd4bf sha1 6e0121c4cb9cb82ca7ee1004f90f9954f062d927 ) +) + +game ( + name "Minolta 2166 Adj. Program (USA) (Unl)" + description "Minolta 2166 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2166 Adj. Program (USA) (Unl).gb" size 32768 crc 711179d9 sha1 dd48d1cb7218bda09d59247f4b0eb6832a611e51 ) +) + +game ( + name "Minolta 2181 Adj. Program (USA) (Unl)" + description "Minolta 2181 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2181 Adj. Program (USA) (Unl).gb" size 32768 crc ac64f965 sha1 14d85a2943a2caedb559ccd48f3c3536b7c54a18 ) +) + +game ( + name "Minolta 2205 Adj. Program (USA) (Unl)" + description "Minolta 2205 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2205 Adj. Program (USA) (Unl).gb" size 32768 crc d70cc276 sha1 48a417f53bb7852d7278f37b4a75c8da695db5d6 ) +) + +game ( + name "Minolta 2419 Adj. Program (USA) (Unl)" + description "Minolta 2419 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2419 Adj. Program (USA) (Unl).gb" size 32768 crc f9373901 sha1 c4fdbdc3a2b7cdd4b494ece7f81d88f5d7564c3d ) +) + +game ( + name "Minolta 2420 Adj. Program (USA) (Unl)" + description "Minolta 2420 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2420 Adj. Program (USA) (Unl).gb" size 32768 crc 5bd13f4f sha1 b5994db5e190bef18bb7f3d1c25f8b14ef4b9b22 ) +) + +game ( + name "Minolta 2420 Adj. Program2 (USA) (Unl)" + description "Minolta 2420 Adj. Program2 (USA) (Unl)" + rom ( name "Minolta 2420 Adj. Program2 (USA) (Unl).gb" size 32768 crc 97561d80 sha1 a55a5fd97ca1be3fa129f744f81fc972e29418ac ) +) + +game ( + name "Minolta 2428 Adj. Program (USA) (Unl)" + description "Minolta 2428 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2428 Adj. Program (USA) (Unl).gb" size 32768 crc 4abf7bd2 sha1 6192d29c564441ca2b42a06ef15cc6f56e90f90f ) +) + +game ( + name "Minolta 2429 Adj. Program (USA) (Unl)" + description "Minolta 2429 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2429 Adj. Program (USA) (Unl).gb" size 32768 crc e0dc1323 sha1 f3a394cee80a1de435fd3c90e3ca31b0672665f9 ) +) + +game ( + name "Minolta 2440 Adj. Program (USA) (Unl) (Alt)" + description "Minolta 2440 Adj. Program (USA) (Unl) (Alt)" + rom ( name "Minolta 2440 Adj. Program (USA) (Unl) (Alt).gb" size 32768 crc 37c305dc sha1 494b8392c67a6e91ccf198b82b8f9e515dd7e02a ) +) + +game ( + name "Minolta 2440 Adj. Program (USA) (Unl)" + description "Minolta 2440 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2440 Adj. Program (USA) (Unl).gb" size 32768 crc 7a9359ea sha1 c15325e2e0ad2c8bd4323ef2390df28e578dcdb8 ) +) + +game ( + name "Minolta 2463 Adj. Program (USA) (Unl)" + description "Minolta 2463 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2463 Adj. Program (USA) (Unl).gb" size 32768 crc 7e5429d3 sha1 828f068b0fe5d8c88862f505e982e2cb1568689b ) +) + +game ( + name "Minolta 2468 Adj. Program (USA) (Unl)" + description "Minolta 2468 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2468 Adj. Program (USA) (Unl).gb" size 32768 crc cd622b15 sha1 51480e67f459b966bf2e18ec5092c135557c12d7 ) +) + +game ( + name "Minolta 2472-73 Adj. Program (USA) (Unl)" + description "Minolta 2472-73 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2472-73 Adj. Program (USA) (Unl).gb" size 32768 crc 15493e75 sha1 b242bcf33d46b5642392e526d7466e63f0b6a718 ) +) + +game ( + name "Minolta 2476 Adj. Program (USA) (Unl)" + description "Minolta 2476 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2476 Adj. Program (USA) (Unl).gb" size 32768 crc 6c3501df sha1 2ac3148a2593e062ffd8ed116da4eb749277c434 ) +) + +game ( + name "Minolta 2481 Adj. Program (USA) (Unl)" + description "Minolta 2481 Adj. Program (USA) (Unl)" + rom ( name "Minolta 2481 Adj. Program (USA) (Unl).gb" size 32768 crc 67e5a203 sha1 4d1a3176e4232984a14580382152ce5313a620e6 ) +) + +game ( + name "Minolta SLR Data Copy (USA) (Unl)" + description "Minolta SLR Data Copy (USA) (Unl)" + rom ( name "Minolta SLR Data Copy (USA) (Unl).gb" size 32768 crc 76f0ff74 sha1 a0ada0dd3cdfd1e0908e90cd512fa094f5396e1e ) +) + game ( name "Miracle Adventure of Esparks - Ushinawareta Seiseki Perivron (Japan)" description "Miracle Adventure of Esparks - Ushinawareta Seiseki Perivron (Japan)" @@ -27203,15 +28351,21 @@ game ( ) game ( - name "Mission to Mars (World) (Aftermarket) (Homebrew)" - description "Mission to Mars (World) (Aftermarket) (Homebrew)" - rom ( name "Mission to Mars (World) (Aftermarket) (Homebrew).gb" size 262144 crc cb3a9ab8 sha1 31625a90b61d28ac782909ed8b00b3a48df7742e ) + name "Mission Mars (World) (Aftermarket) (Unl)" + description "Mission Mars (World) (Aftermarket) (Unl)" + rom ( name "Mission Mars (World) (Aftermarket) (Unl).gb" size 262144 crc cb3a9ab8 sha1 31625a90b61d28ac782909ed8b00b3a48df7742e ) ) game ( - name "Mofa Qiu (Taiwan) (Unl)" - description "Mofa Qiu (Taiwan) (Unl)" - rom ( name "Mofa Qiu (Taiwan) (Unl).gb" size 131072 crc e2cb3b91 sha1 88ac96eb953d1c273896893c7d8e1597524da4a4 ) + name "Mofa Qiu - Magic Ball (Taiwan) (Multicart Rip) (Unl)" + description "Mofa Qiu - Magic Ball (Taiwan) (Multicart Rip) (Unl)" + rom ( name "Mofa Qiu - Magic Ball (Taiwan) (Multicart Rip) (Unl).gb" size 131072 crc e2cb3b91 sha1 88ac96eb953d1c273896893c7d8e1597524da4a4 ) +) + +game ( + name "Mofa Qiu - Magic Ball (Taiwan) (Unl)" + description "Mofa Qiu - Magic Ball (Taiwan) (Unl)" + rom ( name "Mofa Qiu - Magic Ball (Taiwan) (Unl).gb" size 65536 crc 38465864 sha1 50c0450b540bb338a71bf626f93005e991929f6e ) ) game ( @@ -27281,9 +28435,9 @@ game ( ) game ( - name "Mona and the Witch's Hat (World) (Aftermarket) (Homebrew)" - description "Mona and the Witch's Hat (World) (Aftermarket) (Homebrew)" - rom ( name "Mona and the Witch's Hat (World) (Aftermarket) (Homebrew).gb" size 65536 crc 32ed7f4a sha1 625d3664d99dee075021b03ea6ff074ae2e49204 ) + name "Mona and the Witch's Hat (World) (Aftermarket) (Unl)" + description "Mona and the Witch's Hat (World) (Aftermarket) (Unl)" + rom ( name "Mona and the Witch's Hat (World) (Aftermarket) (Unl).gb" size 65536 crc 32ed7f4a sha1 625d3664d99dee075021b03ea6ff074ae2e49204 ) ) game ( @@ -27377,9 +28531,9 @@ game ( ) game ( - name "Monty on the Run (World) (Aftermarket) (Homebrew)" - description "Monty on the Run (World) (Aftermarket) (Homebrew)" - rom ( name "Monty on the Run (World) (Aftermarket) (Homebrew).gb" size 524288 crc e2ebb406 sha1 41ac5993fbff58be0712b554aae5e4367b68677b ) + name "Monty on the Run (World) (Aftermarket) (Unl)" + description "Monty on the Run (World) (Aftermarket) (Unl)" + rom ( name "Monty on the Run (World) (Aftermarket) (Unl).gb" size 524288 crc e2ebb406 sha1 41ac5993fbff58be0712b554aae5e4367b68677b ) ) game ( @@ -27460,12 +28614,6 @@ game ( rom ( name "Motocross Maniacs (Europe) (Rev 1).gb" size 32768 crc f867ee3b sha1 d21f2a4ddb69c408a370b6768f83914c11012c71 ) ) -game ( - name "Mountain Climber (World) (Aftermarket) (Homebrew)" - description "Mountain Climber (World) (Aftermarket) (Homebrew)" - rom ( name "Mountain Climber (World) (Aftermarket) (Homebrew).gb" size 262144 crc 362a84ba sha1 b4b3afa2379a07acab6965ae8fcf6d2ba82d6d7e ) -) - game ( name "Mouse Trap Hotel (USA)" description "Mouse Trap Hotel (USA)" @@ -27514,12 +28662,6 @@ game ( rom ( name "Ms. Pac-Man (USA).gb" size 65536 crc 0e5bb1c4 sha1 fcc05f0625d52ace28d21fd8270e71246229cbad ) ) -game ( - name "Mud Warriors (World) (Aftermarket) (Homebrew)" - description "Mud Warriors (World) (Aftermarket) (Homebrew)" - rom ( name "Mud Warriors (World) (Aftermarket) (Homebrew).gb" size 524288 crc 846afc79 sha1 dae84fbc60839da29878714cd845c3704b915323 ) -) - game ( name "Muhammad Ali Heavyweight Boxing (USA, Europe)" description "Muhammad Ali Heavyweight Boxing (USA, Europe)" @@ -27538,6 +28680,12 @@ game ( rom ( name "Mulan (USA) (SGB Enhanced).gb" size 524288 crc bfcf71a1 sha1 7832fcc373ff752e757550079519b39583665c82 ) ) +game ( + name "Muncher (World) (Aftermarket) (Unl)" + description "Muncher (World) (Aftermarket) (Unl)" + rom ( name "Muncher (World) (Aftermarket) (Unl).gb" size 262144 crc 444d3d5e sha1 c3e09aff66c7e395bf95a1864963fbe979d5cb9b ) +) + game ( name "MVP Baseball (Japan)" description "MVP Baseball (Japan)" @@ -27571,7 +28719,7 @@ game ( game ( name "Mystic Quest (France)" description "Mystic Quest (France)" - rom ( name "Mystic Quest (France).gb" size 262144 crc b6e134af sha1 b52d82248849f1ead9bf22954b3cbf7bf8e02907 ) + rom ( name "Mystic Quest (France).gb" size 262144 crc b6e134af sha1 b52d82248849f1ead9bf22954b3cbf7bf8e02907 flags verified ) ) game ( @@ -27766,6 +28914,24 @@ game ( rom ( name "Nekketsu! Beach Volley Da yo Kunio-kun (Japan) (SGB Enhanced).gb" size 262144 crc abfb84df sha1 d3ad43c40c21d9825b4879dbf28ca58835da658a ) ) +game ( + name "Neko Can Dream (World) (Aftermarket) (Unl)" + description "Neko Can Dream (World) (Aftermarket) (Unl)" + rom ( name "Neko Can Dream (World) (Aftermarket) (Unl).gb" size 2097152 crc 6e76ef25 sha1 55686fde78d17d00adfc831eca2c699274a82273 ) +) + +game ( + name "Neko Can Dream (World) (Ja) (Demo) (Aftermarket) (Unl)" + description "Neko Can Dream (World) (Ja) (Demo) (Aftermarket) (Unl)" + rom ( name "Neko Can Dream (World) (Ja) (Demo) (Aftermarket) (Unl).gb" size 2097152 crc a0ad7a18 sha1 5fb1a09e04cf1704b059468de8855dfa7e23043b ) +) + +game ( + name "Neko Can Dream (World) (Demo) (Aftermarket) (Unl)" + description "Neko Can Dream (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Neko Can Dream (World) (Demo) (Aftermarket) (Unl).gb" size 2097152 crc dc011d07 sha1 43312b149355d20944e8a366584c69e5cb3be868 ) +) + game ( name "Nekojara Monogatari (Japan)" description "Nekojara Monogatari (Japan)" @@ -28097,9 +29263,21 @@ game ( ) game ( - name "Oblique Strategies (World) (Aftermarket) (Homebrew)" - description "Oblique Strategies (World) (Aftermarket) (Homebrew)" - rom ( name "Oblique Strategies (World) (Aftermarket) (Homebrew).gb" size 524288 crc 30eca8d3 sha1 6a09aabf30e2ebab2e31ae845cd2e8796c84797f ) + name "Nyghtmare - Betrayed (World) (Alpha A) (Aftermarket) (Unl)" + description "Nyghtmare - Betrayed (World) (Alpha A) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - Betrayed (World) (Alpha A) (Aftermarket) (Unl).gb" size 262144 crc d6166c62 sha1 fa2198c5308a15195adbda004f09646589860d11 ) +) + +game ( + name "Nyghtmare - Betrayed (World) (v0.1.1) (Beta) (Aftermarket) (Unl)" + description "Nyghtmare - Betrayed (World) (v0.1.1) (Beta) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - Betrayed (World) (v0.1.1) (Beta) (Aftermarket) (Unl).gb" size 1048576 crc 42b47080 sha1 08484b0f98e72d6577d9b7cde8c49908012d1fc5 ) +) + +game ( + name "Oblique Strategies (World) (Aftermarket) (Unl)" + description "Oblique Strategies (World) (Aftermarket) (Unl)" + rom ( name "Oblique Strategies (World) (Aftermarket) (Unl).gb" size 524288 crc 30eca8d3 sha1 6a09aabf30e2ebab2e31ae845cd2e8796c84797f ) ) game ( @@ -28109,9 +29287,21 @@ game ( ) game ( - name "Office Combat (World) (Aftermarket) (Homebrew)" - description "Office Combat (World) (Aftermarket) (Homebrew)" - rom ( name "Office Combat (World) (Aftermarket) (Homebrew).gb" size 262144 crc 9742276d sha1 cd8f18d6e5fabaa130a42e5618e29c5ff26f6a93 ) + name "Oiopolis (World) (Es) (Demo) (Aftermarket) (Unl)" + description "Oiopolis (World) (Es) (Demo) (Aftermarket) (Unl)" + rom ( name "Oiopolis (World) (Es) (Demo) (Aftermarket) (Unl).gb" size 524288 crc d3eba01d sha1 8cf234bbcb68ca2b676a4ccec89814b0cbce1c07 ) +) + +game ( + name "Oiopolis (World) (En) (Demo) (Aftermarket) (Unl)" + description "Oiopolis (World) (En) (Demo) (Aftermarket) (Unl)" + rom ( name "Oiopolis (World) (En) (Demo) (Aftermarket) (Unl).gb" size 524288 crc 71f34822 sha1 f24da97f44d280f27f8ebe3acdc33fea758d2255 ) +) + +game ( + name "Oiopolis (World) (Ca) (Demo) (Aftermarket) (Unl)" + description "Oiopolis (World) (Ca) (Demo) (Aftermarket) (Unl)" + rom ( name "Oiopolis (World) (Ca) (Demo) (Aftermarket) (Unl).gb" size 524288 crc 76baab68 sha1 cd76da35541535dd244ad60d10eb998f7692f07a ) ) game ( @@ -28121,9 +29311,9 @@ game ( ) game ( - name "Olympic Skier (World) (Aftermarket) (Homebrew)" - description "Olympic Skier (World) (Aftermarket) (Homebrew)" - rom ( name "Olympic Skier (World) (Aftermarket) (Homebrew).gb" size 524288 crc 93174431 sha1 7bcdf10533f8fe053e22534c4962ed4b1a5cf2e2 ) + name "Olympic Skier (World) (Aftermarket) (Unl)" + description "Olympic Skier (World) (Aftermarket) (Unl)" + rom ( name "Olympic Skier (World) (Aftermarket) (Unl).gb" size 524288 crc 93174431 sha1 7bcdf10533f8fe053e22534c4962ed4b1a5cf2e2 ) ) game ( @@ -28234,6 +29424,18 @@ game ( rom ( name "Out of Gas (USA).gb" size 131072 crc 1b67e8b1 sha1 770ac35c0780cf432235593bd5674e72edd6cf7d ) ) +game ( + name "Out on a Limb (World) (Aftermarket) (Unl)" + description "Out on a Limb (World) (Aftermarket) (Unl)" + rom ( name "Out on a Limb (World) (Aftermarket) (Unl).gb" size 262144 crc be197f87 sha1 2ddc2378539316cf7a10e2cf8b562f17e1cf7a6a ) +) + +game ( + name "Outburst (Japan) (Demo)" + description "Outburst (Japan) (Demo)" + rom ( name "Outburst (Japan) (Demo).gb" size 262144 crc 9837ffac sha1 4a45cc555b486f5dafa4e844a7b6afceb709a1b9 ) +) + game ( name "Outburst (Japan)" description "Outburst (Japan)" @@ -28277,9 +29479,9 @@ game ( ) game ( - name "Pac-In-Time (Europe) (Rev 1) (Possible Proto) (SGB Enhanced)" - description "Pac-In-Time (Europe) (Rev 1) (Possible Proto) (SGB Enhanced)" - rom ( name "Pac-In-Time (Europe) (Rev 1) (Possible Proto) (SGB Enhanced).gb" size 262144 crc 7ff79df9 sha1 f30108b8e422c4b9776c90c884710194508545ea ) + name "Pac-In-Time (Europe) (Rev 1) (SGB Enhanced)" + description "Pac-In-Time (Europe) (Rev 1) (SGB Enhanced)" + rom ( name "Pac-In-Time (Europe) (Rev 1) (SGB Enhanced).gb" size 262144 crc 7ff79df9 sha1 f30108b8e422c4b9776c90c884710194508545ea ) ) game ( @@ -28468,6 +29670,12 @@ game ( rom ( name "Pang (Europe) (Beta).gb" size 131072 crc 54d2754a sha1 b57d436d8a83f2fb1e42bad3150893ef8ffab0d4 ) ) +game ( + name "Panty Hunty (World) (v1.4) (Aftermarket) (Unl)" + description "Panty Hunty (World) (v1.4) (Aftermarket) (Unl)" + rom ( name "Panty Hunty (World) (v1.4) (Aftermarket) (Unl).gb" size 524288 crc ce707b9a sha1 b5757b268a09d9085d469eda0676991f7361ad8c ) +) + game ( name "Paperboy (USA, Europe)" description "Paperboy (USA, Europe)" @@ -28487,9 +29695,9 @@ game ( ) game ( - name "Parasol Islands (World) (Aftermarket) (Homebrew)" - description "Parasol Islands (World) (Aftermarket) (Homebrew)" - rom ( name "Parasol Islands (World) (Aftermarket) (Homebrew).gb" size 1048576 crc b1d79c80 sha1 381f76af67f77e575beae2f45aefd21f079709e6 ) + name "Parasol Islands (World) (Aftermarket) (Unl)" + description "Parasol Islands (World) (Aftermarket) (Unl)" + rom ( name "Parasol Islands (World) (Aftermarket) (Unl).gb" size 1048576 crc b1d79c80 sha1 381f76af67f77e575beae2f45aefd21f079709e6 ) ) game ( @@ -28547,15 +29755,15 @@ game ( ) game ( - name "Perfect Blend (World) (Aftermarket) (Homebrew)" - description "Perfect Blend (World) (Aftermarket) (Homebrew)" - rom ( name "Perfect Blend (World) (Aftermarket) (Homebrew).gb" size 262144 crc 9b4bacaa sha1 09b0691f6823c54f1515dd3b66f135ac45a7dbc3 ) + name "Perfect Blend (World) (v0.9) (Aftermarket) (Unl)" + description "Perfect Blend (World) (v0.9) (Aftermarket) (Unl)" + rom ( name "Perfect Blend (World) (v0.9) (Aftermarket) (Unl).gb" size 262144 crc 9b4bacaa sha1 09b0691f6823c54f1515dd3b66f135ac45a7dbc3 ) ) game ( - name "Perfect Blend (World) (Rev 1) (Aftermarket) (Homebrew)" - description "Perfect Blend (World) (Rev 1) (Aftermarket) (Homebrew)" - rom ( name "Perfect Blend (World) (Rev 1) (Aftermarket) (Homebrew).gb" size 262144 crc 1e8b2a29 sha1 a25dfc43408080ac116479fa55c9e7320e5cc82a ) + name "Perfect Blend (World) (v0.9) (Bugfix) (Aftermarket) (Unl)" + description "Perfect Blend (World) (v0.9) (Bugfix) (Aftermarket) (Unl)" + rom ( name "Perfect Blend (World) (v0.9) (Bugfix) (Aftermarket) (Unl).gb" size 262144 crc 1e8b2a29 sha1 a25dfc43408080ac116479fa55c9e7320e5cc82a ) ) game ( @@ -28582,12 +29790,6 @@ game ( rom ( name "Phantom Air Mission (Europe).gb" size 131072 crc 8aced4a6 sha1 2a270597d7b814a1c8819a5698ab922200569206 flags verified ) ) -game ( - name "Phantom Fright (World) (Aftermarket) (Homebrew)" - description "Phantom Fright (World) (Aftermarket) (Homebrew)" - rom ( name "Phantom Fright (World) (Aftermarket) (Homebrew).gb" size 524288 crc 154cb547 sha1 3b217c595e6a5b115dc7130123a321049cf01d22 ) -) - game ( name "Philip & Marlowe in Bloomland (USA) (Proto)" description "Philip & Marlowe in Bloomland (USA) (Proto)" @@ -28595,15 +29797,15 @@ game ( ) game ( - name "Phobos Dere .GB (World) (Rev 1) (Demo) (Aftermarket) (Homebrew)" - description "Phobos Dere .GB (World) (Rev 1) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Phobos Dere .GB (World) (Rev 1) (Demo) (Aftermarket) (Homebrew).gbc" size 262144 crc 58362b86 sha1 b4cc3c3735bc134e34b97e08ed24c57aef5c5ccf flags verified ) + name "Phobos Dere .GB (World) (Aftermarket) (Unl)" + description "Phobos Dere .GB (World) (Aftermarket) (Unl)" + rom ( name "Phobos Dere .GB (World) (Aftermarket) (Unl).gb" size 1048576 crc ae97f4f8 sha1 e541505078ee5e7e5c897b4621cc693ce71e35ba flags verified ) ) game ( - name "Phobos Dere .GB (World) (Aftermarket) (Homebrew)" - description "Phobos Dere .GB (World) (Aftermarket) (Homebrew)" - rom ( name "Phobos Dere .GB (World) (Aftermarket) (Homebrew).gbc" size 1048576 crc ae97f4f8 sha1 e541505078ee5e7e5c897b4621cc693ce71e35ba ) + name "Phobos Dere .GB (World) (2022-03-06) (Demo) (Aftermarket) (Unl)" + description "Phobos Dere .GB (World) (2022-03-06) (Demo) (Aftermarket) (Unl)" + rom ( name "Phobos Dere .GB (World) (2022-03-06) (Demo) (Aftermarket) (Unl).gb" size 262144 crc 58362b86 sha1 b4cc3c3735bc134e34b97e08ed24c57aef5c5ccf flags verified ) ) game ( @@ -28660,6 +29862,18 @@ game ( rom ( name "Pinball Mania (Europe).gb" size 262144 crc edc8d122 sha1 0541161b4b93fffc3c75708aca86ea0873747ced ) ) +game ( + name "Pineapple Kid (World) (Aftermarket) (Unl)" + description "Pineapple Kid (World) (Aftermarket) (Unl)" + rom ( name "Pineapple Kid (World) (Aftermarket) (Unl).gb" size 131072 crc 9541488b sha1 fd574b5d407f3654db3227900a8ed7eff4fe48ae ) +) + +game ( + name "Pineapple Kid (World) (Demo) (Aftermarket) (Unl)" + description "Pineapple Kid (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Pineapple Kid (World) (Demo) (Aftermarket) (Unl).gb" size 131072 crc 9d9102d9 sha1 105e78f740d6bc517ef0079f867e9fdce8d012d2 ) +) + game ( name "Pingu - Sekai de 1ban Genki na Penguin (Japan)" description "Pingu - Sekai de 1ban Genki na Penguin (Japan)" @@ -28681,7 +29895,7 @@ game ( game ( name "Pipe Dream (Japan)" description "Pipe Dream (Japan)" - rom ( name "Pipe Dream (Japan).gb" size 32768 crc d8b4aea4 sha1 64a58aafecb0aceed2dde843a19a28b2bb000b2f ) + rom ( name "Pipe Dream (Japan).gb" size 32768 crc d8b4aea4 sha1 64a58aafecb0aceed2dde843a19a28b2bb000b2f flags verified ) ) game ( @@ -28703,9 +29917,15 @@ game ( ) game ( - name "Pixel Who - The Lost Legions (World) (v1.0) (Aftermarket) (Homebrew)" - description "Pixel Who - The Lost Legions (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Pixel Who - The Lost Legions (World) (v1.0) (Aftermarket) (Homebrew).gb" size 1048576 crc f41cf2a7 sha1 c07378c774602060f1f93f18fbfd3f0d552fe2d2 ) + name "Pixel Who - The Lost Legions (World) (Aftermarket) (Unl)" + description "Pixel Who - The Lost Legions (World) (Aftermarket) (Unl)" + rom ( name "Pixel Who - The Lost Legions (World) (Aftermarket) (Unl).gb" size 1048576 crc f41cf2a7 sha1 c07378c774602060f1f93f18fbfd3f0d552fe2d2 ) +) + +game ( + name "Plants Eat My Zombies (World) (v1.1) (Aftermarket) (Unl)" + description "Plants Eat My Zombies (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Plants Eat My Zombies (World) (v1.1) (Aftermarket) (Unl).gb" size 524288 crc 60c84f2e sha1 c39ec5e6a9a0be0970b56e788c3f60e9821dbbd3 ) ) game ( @@ -28715,9 +29935,9 @@ game ( ) game ( - name "Pluto's Corner (World) (Aftermarket) (Homebrew)" - description "Pluto's Corner (World) (Aftermarket) (Homebrew)" - rom ( name "Pluto's Corner (World) (Aftermarket) (Homebrew).gb" size 65536 crc 21fc06b3 sha1 94e4a442205079d85d5ca37042eaec555f7f49db ) + name "Pluto's Corner (World) (Aftermarket) (Unl)" + description "Pluto's Corner (World) (Aftermarket) (Unl)" + rom ( name "Pluto's Corner (World) (Aftermarket) (Unl).gb" size 65536 crc 21fc06b3 sha1 94e4a442205079d85d5ca37042eaec555f7f49db ) ) game ( @@ -28753,7 +29973,13 @@ game ( game ( name "Pocket Camera (Japan) (Rev 1) (SGB Enhanced)" description "Pocket Camera (Japan) (Rev 1) (SGB Enhanced)" - rom ( name "Pocket Camera (Japan) (Rev 1) (SGB Enhanced).gb" size 1048576 crc 73e8ef96 sha1 912205ea22e1dd735ed4f41d247039eebf39dddc ) + rom ( name "Pocket Camera (Japan) (Rev 1) (SGB Enhanced).gb" size 1048576 crc 73e8ef96 sha1 912205ea22e1dd735ed4f41d247039eebf39dddc flags verified ) +) + +game ( + name "Pocket Camera - Debug Game Tester - Second Impact (Japan) (Test Program) (v10.24) (SGB Enhanced)" + description "Pocket Camera - Debug Game Tester - Second Impact (Japan) (Test Program) (v10.24) (SGB Enhanced)" + rom ( name "Pocket Camera - Debug Game Tester - Second Impact (Japan) (Test Program) (v10.24) (SGB Enhanced).gb" size 1048576 crc 15726d8c sha1 5ffcda6fa1a3d87c5cbb8ddf743ddbc18242443b ) ) game ( @@ -28822,6 +30048,12 @@ game ( rom ( name "Pocket Monsters - Ao (Japan) (SGB Enhanced).gb" size 524288 crc e4468d14 sha1 0da501e3e5c51ab8fef55b092dcdd7e6b050e424 flags verified ) ) +game ( + name "Pocket Monsters - Green Version - English Edition (Taiwan) (En) (Pirate)" + description "Pocket Monsters - Green Version - English Edition (Taiwan) (En) (Pirate)" + rom ( name "Pocket Monsters - Green Version - English Edition (Taiwan) (En) (Pirate).gb" size 786432 crc 742357fc sha1 b8d1b89a82fbad0352f4a15dd1bcc91868717578 ) +) + game ( name "Pocket Monsters - Midori (Japan) (SGB Enhanced)" description "Pocket Monsters - Midori (Japan) (SGB Enhanced)" @@ -28919,9 +30151,9 @@ game ( ) game ( - name "Pogo Pete (World) (Aftermarket) (Homebrew)" - description "Pogo Pete (World) (Aftermarket) (Homebrew)" - rom ( name "Pogo Pete (World) (Aftermarket) (Homebrew).gb" size 262144 crc 185ce1d5 sha1 74021e84c1d095b2401302e26352e810dbc432d8 ) + name "Pogo Pete (World) (Aftermarket) (Unl)" + description "Pogo Pete (World) (Aftermarket) (Unl)" + rom ( name "Pogo Pete (World) (Aftermarket) (Unl).gb" size 262144 crc 185ce1d5 sha1 74021e84c1d095b2401302e26352e810dbc432d8 ) ) game ( @@ -29026,6 +30258,60 @@ game ( rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (CGB+SGB Enhanced).gb" size 1048576 crc 7d527d62 sha1 cc7d03262ebfaf2f06772c1a480c7d9d5f4a38e1 flags verified ) ) +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-22) (Beta) (CGB+SGB Enhanced) (Alt)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-22) (Beta) (CGB+SGB Enhanced) (Alt)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-22) (Beta) (CGB+SGB Enhanced) (Alt).gb" size 1048576 crc dbd0b8dc sha1 ad2ec0171cc731747adbe51b852a0bc6acd9471a ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-03) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-03) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-03) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc d0b1e29b sha1 7c4ef696e2d0d965d5c6f33e745bbacc1715bba1 ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-03) (Beta) (CGB+SGB Enhanced) (Alt)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-03) (Beta) (CGB+SGB Enhanced) (Alt)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-03) (Beta) (CGB+SGB Enhanced) (Alt).gb" size 1048576 crc 1116ae9f sha1 bfac8de19d04e859f64aaa52ffb1f3d5094417ff ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-18) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-18) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-18) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc b539a028 sha1 53dcd8b02c7ad002a7c40edf758b19d3b393a9c4 ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-15) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-15) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-15) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc 00787832 sha1 13ef81f63904d496c6d6acf6685750ecdb35357b ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-16) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-16) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-16) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc 42c5430a sha1 d8a7d2ec6a8dd9f8e97cf02a27882a750650aa6c ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-22) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-22) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-22) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc c83df319 sha1 490a925fe4e30dc0217c4a23ed9b4f41538277db ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-17) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-17) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-17) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc 0dee0d87 sha1 bde79c92c801cc0c0e73a022bdf23f086b4da4c5 ) +) + +game ( + name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-10) (Beta) (CGB+SGB Enhanced)" + description "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-10) (Beta) (CGB+SGB Enhanced)" + rom ( name "Pokemon - Yellow Version - Special Pikachu Edition (USA, Europe) (1999-02-10) (Beta) (CGB+SGB Enhanced).gb" size 1048576 crc 2e63bc59 sha1 834e933256855403da07d88d375cdbe88d628f01 ) +) + game ( name "Pokonyan! - Yume no Daibouken (Japan) (SGB Enhanced)" description "Pokonyan! - Yume no Daibouken (Japan) (SGB Enhanced)" @@ -29050,6 +30336,12 @@ game ( rom ( name "Pop'n TwinBee (Europe).gb" size 131072 crc d07db274 sha1 0206230b55c15a8c18fbb85f852967e44b33a0a4 ) ) +game ( + name "Popcorn Caravan (World) (Demo) (Aftermarket) (Unl)" + description "Popcorn Caravan (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Popcorn Caravan (World) (Demo) (Aftermarket) (Unl).gb" size 65536 crc ead528f9 sha1 909d3421747d211a2dc70918d2c952db953e49b2 ) +) + game ( name "Popeye (Japan)" description "Popeye (Japan)" @@ -29105,9 +30397,21 @@ game ( ) game ( - name "Porklike (World) (Aftermarket) (Homebrew)" - description "Porklike (World) (Aftermarket) (Homebrew)" - rom ( name "Porklike (World) (Aftermarket) (Homebrew).gb" size 65536 crc 6c57e55e sha1 143f31656a5007f65b19d6e32967698bb8f72a66 ) + name "Porklike (World) (v1.0.3) (Aftermarket) (Unl)" + description "Porklike (World) (v1.0.3) (Aftermarket) (Unl)" + rom ( name "Porklike (World) (v1.0.3) (Aftermarket) (Unl).gb" size 65536 crc 6c57e55e sha1 143f31656a5007f65b19d6e32967698bb8f72a66 ) +) + +game ( + name "Porklike (World) (v1.0.9) (SGB Enhanced) (Aftermarket) (Unl)" + description "Porklike (World) (v1.0.9) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Porklike (World) (v1.0.9) (SGB Enhanced) (Aftermarket) (Unl).gb" size 65536 crc 7aaa853a sha1 0868bffd52b2bdc5601ab6cf1e25f40924ca643d ) +) + +game ( + name "Porklike (World) (v1.05) (SGB Enhanced) (Aftermarket) (Unl)" + description "Porklike (World) (v1.05) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Porklike (World) (v1.05) (SGB Enhanced) (Aftermarket) (Unl).gb" size 65536 crc 801f097b sha1 5da110a88799765707e027bcedec0875a637509b ) ) game ( @@ -29212,6 +30516,12 @@ game ( rom ( name "Prince of Persia (Europe) (En,Fr,De,Es,It) (Beta).gb" size 131072 crc e0aaad99 sha1 42b6dfbf283946998caa6c383fa70bf1b646217e ) ) +game ( + name "Prince of Persia (USA) (Beta)" + description "Prince of Persia (USA) (Beta)" + rom ( name "Prince of Persia (USA) (Beta).gb" size 131072 crc c81ca14b sha1 355709bd9d4b19be5ee57bd62a0b58b73b25e0bf ) +) + game ( name "Prince YehRude (Taiwan) (Unl)" description "Prince YehRude (Taiwan) (Unl)" @@ -29227,7 +30537,7 @@ game ( game ( name "Pro Mahjong Kiwame GB (Japan) (SGB Enhanced)" description "Pro Mahjong Kiwame GB (Japan) (SGB Enhanced)" - rom ( name "Pro Mahjong Kiwame GB (Japan) (SGB Enhanced).gb" size 131072 crc 6f5b6748 sha1 dc6b304ac4e9b679272f843411ba964b438a69b6 ) + rom ( name "Pro Mahjong Kiwame GB (Japan) (SGB Enhanced).gb" size 131072 crc 6f5b6748 sha1 dc6b304ac4e9b679272f843411ba964b438a69b6 flags verified ) ) game ( @@ -29315,9 +30625,15 @@ game ( ) game ( - name "Pushingo (World) (Aftermarket) (Homebrew)" - description "Pushingo (World) (Aftermarket) (Homebrew)" - rom ( name "Pushingo (World) (Aftermarket) (Homebrew).gb" size 262144 crc a8541ed0 sha1 1ac1e22b191a95fdfa00c34ccba7387c991c827b ) + name "Purple Turtles (World) (Aftermarket) (Unl)" + description "Purple Turtles (World) (Aftermarket) (Unl)" + rom ( name "Purple Turtles (World) (Aftermarket) (Unl).gb" size 262144 crc f7041a97 sha1 d2d7eff063104c8f205c192a902a53092c0b5f4a ) +) + +game ( + name "Pushingo (World) (Aftermarket) (Unl)" + description "Pushingo (World) (Aftermarket) (Unl)" + rom ( name "Pushingo (World) (Aftermarket) (Unl).gb" size 262144 crc a8541ed0 sha1 1ac1e22b191a95fdfa00c34ccba7387c991c827b ) ) game ( @@ -29404,12 +30720,6 @@ game ( rom ( name "QIX (World).gb" size 65536 crc 9185e89e sha1 fb9935ca821562966eafa8f60ec2f489ad33940a flags verified ) ) -game ( - name "Quartet (World) (Aftermarket) (Homebrew)" - description "Quartet (World) (Aftermarket) (Homebrew)" - rom ( name "Quartet (World) (Aftermarket) (Homebrew).gb" size 32768 crc 46743216 sha1 bf866b438a602af386f8fad02727b4084edf6047 ) -) - game ( name "Quarth (Japan)" description "Quarth (Japan)" @@ -29423,9 +30733,9 @@ game ( ) game ( - name "Quest Arrest (World) (v1.1) (Aftermarket) (Homebrew)" - description "Quest Arrest (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Quest Arrest (World) (v1.1) (Aftermarket) (Homebrew).gb" size 1048576 crc 9ac546d5 sha1 25b3a21135bfc7587c096b10f4a20d8b3095d721 ) + name "Quick Draw (World) (Aftermarket) (Unl)" + description "Quick Draw (World) (Aftermarket) (Unl)" + rom ( name "Quick Draw (World) (Aftermarket) (Unl).gb" size 262144 crc 7704671f sha1 75f96ce54ed8739d58153780e9b573a65f1c5880 ) ) game ( @@ -29455,7 +30765,7 @@ game ( game ( name "R-Type II (Europe)" description "R-Type II (Europe)" - rom ( name "R-Type II (Europe).gb" size 131072 crc 2fe2a72d sha1 f19436dfed41b9c2e94e070a76c5bdbcc7f993c3 ) + rom ( name "R-Type II (Europe).gb" size 131072 crc 2fe2a72d sha1 f19436dfed41b9c2e94e070a76c5bdbcc7f993c3 flags verified ) ) game ( @@ -29503,7 +30813,7 @@ game ( game ( name "Racing Damashii (Japan)" description "Racing Damashii (Japan)" - rom ( name "Racing Damashii (Japan).gb" size 65536 crc 796fbb66 sha1 4466b36294176b3e1fc1558cd00abdfa4247a75d ) + rom ( name "Racing Damashii (Japan).gb" size 65536 crc 796fbb66 sha1 4466b36294176b3e1fc1558cd00abdfa4247a75d flags verified ) ) game ( @@ -29512,6 +30822,12 @@ game ( rom ( name "Radar Mission (USA, Europe).gb" size 131072 crc 581da9c9 sha1 5ab5998a84eebc769f75c482cb0a5586ed97e888 ) ) +game ( + name "Raffles (World) (Aftermarket) (Unl)" + description "Raffles (World) (Aftermarket) (Unl)" + rom ( name "Raffles (World) (Aftermarket) (Unl).gb" size 262144 crc 0b400a91 sha1 aadfe3fd0720696547b73b272354b592b96f98f7 ) +) + game ( name "Raging Fighter (USA, Europe)" description "Raging Fighter (USA, Europe)" @@ -29579,9 +30895,9 @@ game ( ) game ( - name "Remute - Living Electronics (World) (Aftermarket) (Homebrew)" - description "Remute - Living Electronics (World) (Aftermarket) (Homebrew)" - rom ( name "Remute - Living Electronics (World) (Aftermarket) (Homebrew).gb" size 2097152 crc 1ced0a62 sha1 bc4bf12344d3b9d028a7013c84b94aea515be196 ) + name "Remute - Living Electronics (World) (Aftermarket) (Unl)" + description "Remute - Living Electronics (World) (Aftermarket) (Unl)" + rom ( name "Remute - Living Electronics (World) (Aftermarket) (Unl).gb" size 2097152 crc 1ced0a62 sha1 bc4bf12344d3b9d028a7013c84b94aea515be196 flags verified ) ) game ( @@ -29615,21 +30931,27 @@ game ( ) game ( - name "Rewind Time (World) (Aftermarket) (Homebrew)" - description "Rewind Time (World) (Aftermarket) (Homebrew)" - rom ( name "Rewind Time (World) (Aftermarket) (Homebrew).gb" size 262144 crc d8ad184a sha1 903ef8074e58a52bc98dcb9e3f2c88b52fc1335b ) + name "Retroid (World) (Aftermarket) (Unl)" + description "Retroid (World) (Aftermarket) (Unl)" + rom ( name "Retroid (World) (Aftermarket) (Unl).gb" size 262144 crc 9f759f25 sha1 4c7323d6a10852fe416c7bd581d6ffdd2d473bb5 ) ) game ( - name "Rhythm Land (World) (v1.0) (Aftermarket) (Homebrew)" - description "Rhythm Land (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Rhythm Land (World) (v1.0) (Aftermarket) (Homebrew).gb" size 131072 crc 4312c7ff sha1 c79f26ce187edea18cf92be8340ec0a0c8beec87 ) + name "Rewind Time (World) (Aftermarket) (Unl)" + description "Rewind Time (World) (Aftermarket) (Unl)" + rom ( name "Rewind Time (World) (Aftermarket) (Unl).gb" size 262144 crc d8ad184a sha1 903ef8074e58a52bc98dcb9e3f2c88b52fc1335b ) ) game ( - name "Rhythm Land (World) (v1.01) (Aftermarket) (Homebrew)" - description "Rhythm Land (World) (v1.01) (Aftermarket) (Homebrew)" - rom ( name "Rhythm Land (World) (v1.01) (Aftermarket) (Homebrew).gb" size 131072 crc fbf98400 sha1 1b831806d32e1ec35bc94a84384c6989433a274d ) + name "Rhythm Land (World) (Aftermarket) (Unl)" + description "Rhythm Land (World) (Aftermarket) (Unl)" + rom ( name "Rhythm Land (World) (Aftermarket) (Unl).gb" size 131072 crc 4312c7ff sha1 c79f26ce187edea18cf92be8340ec0a0c8beec87 ) +) + +game ( + name "Rhythm Land (World) (v1.0.1) (Aftermarket) (Unl)" + description "Rhythm Land (World) (v1.0.1) (Aftermarket) (Unl)" + rom ( name "Rhythm Land (World) (v1.0.1) (Aftermarket) (Unl).gb" size 131072 crc fbf98400 sha1 1b831806d32e1ec35bc94a84384c6989433a274d ) ) game ( @@ -29651,9 +30973,9 @@ game ( ) game ( - name "Rig Attack (World) (Aftermarket) (Homebrew)" - description "Rig Attack (World) (Aftermarket) (Homebrew)" - rom ( name "Rig Attack (World) (Aftermarket) (Homebrew).gb" size 262144 crc dea8749d sha1 6f0fbac6b6c2e8f2d8df0a0a0e2f0c947e37b39a ) + name "Rig Attack (World) (Aftermarket) (Unl)" + description "Rig Attack (World) (Aftermarket) (Unl)" + rom ( name "Rig Attack (World) (Aftermarket) (Unl).gb" size 262144 crc dea8749d sha1 6f0fbac6b6c2e8f2d8df0a0a0e2f0c947e37b39a ) ) game ( @@ -29687,9 +31009,9 @@ game ( ) game ( - name "Robby's Day Out (World) (Aftermarket) (Homebrew)" - description "Robby's Day Out (World) (Aftermarket) (Homebrew)" - rom ( name "Robby's Day Out (World) (Aftermarket) (Homebrew).gb" size 262144 crc c3c89cd9 sha1 9d38b69ab9a4ff7bf387c88f2afed410d450f2e0 ) + name "Robby's Day Out (World) (Aftermarket) (Unl)" + description "Robby's Day Out (World) (Aftermarket) (Unl)" + rom ( name "Robby's Day Out (World) (Aftermarket) (Unl).gb" size 262144 crc c3c89cd9 sha1 9d38b69ab9a4ff7bf387c88f2afed410d450f2e0 ) ) game ( @@ -29848,6 +31170,18 @@ game ( rom ( name "Rolan's Curse II (USA).gb" size 131072 crc 2754f360 sha1 7632e23853dd2579012489f75bd370473f0f2c46 flags verified ) ) +game ( + name "Roommate Simulator (World) (Aftermarket) (Unl)" + description "Roommate Simulator (World) (Aftermarket) (Unl)" + rom ( name "Roommate Simulator (World) (Aftermarket) (Unl).gb" size 131072 crc 3c95b1aa sha1 d5c99106c3bd4d46aeb75f513fd4314c19c734b2 ) +) + +game ( + name "Rosa Cupiditatis (World) (2023-05-17) (Demo) (Aftermarket) (Unl)" + description "Rosa Cupiditatis (World) (2023-05-17) (Demo) (Aftermarket) (Unl)" + rom ( name "Rosa Cupiditatis (World) (2023-05-17) (Demo) (Aftermarket) (Unl).gb" size 524288 crc 51d09337 sha1 9e935cca00cb4c3aad7b1dfce9fe59f5d913bdff ) +) + game ( name "Rubble Saver (Japan)" description "Rubble Saver (Japan)" @@ -29887,7 +31221,7 @@ game ( game ( name "Sa-Ga 3 - Jikuu no Hasha (Japan)" description "Sa-Ga 3 - Jikuu no Hasha (Japan)" - rom ( name "Sa-Ga 3 - Jikuu no Hasha (Japan).gb" size 262144 crc 575d6d9d sha1 c8dcbefc0352b0590fd85a683d983b5510a63519 ) + rom ( name "Sa-Ga 3 - Jikuu no Hasha (Japan).gb" size 262144 crc 575d6d9d sha1 c8dcbefc0352b0590fd85a683d983b5510a63519 flags verified ) ) game ( @@ -29896,6 +31230,24 @@ game ( rom ( name "Sa-Ga 3 - Jikuu no Hasha (World) (Ja) (Collection of SaGa).gb" size 262144 crc dc4f4e34 sha1 8125677ee63e9abb4b956ed0bee18fae3e04193b ) ) +game ( + name "Sacred Meat (World) (v1.3) (Aftermarket) (Unl)" + description "Sacred Meat (World) (v1.3) (Aftermarket) (Unl)" + rom ( name "Sacred Meat (World) (v1.3) (Aftermarket) (Unl).gb" size 2097152 crc 6669f0be sha1 25bcf936e8dadb10d288473989891e4f2ec6c605 ) +) + +game ( + name "Sacred Meat (World) (v1.1) (Aftermarket) (Unl)" + description "Sacred Meat (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Sacred Meat (World) (v1.1) (Aftermarket) (Unl).gb" size 2097152 crc 1c4b7eb0 sha1 5cd15f4629fdbcfd6f752d89be755d5ac02b9435 ) +) + +game ( + name "Safe File (World) (SGB Enhanced) (Aftermarket) (Unl)" + description "Safe File (World) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Safe File (World) (SGB Enhanced) (Aftermarket) (Unl).gb" size 262144 crc 03f2dd1a sha1 78fe9c7cd6d0d7f1157c8c7716642d17c4b80303 ) +) + game ( name "Sagaia (Japan)" description "Sagaia (Japan)" @@ -29921,9 +31273,9 @@ game ( ) game ( - name "Sam Mallard - The Case of the Missing Swan (World) (Aftermarket) (Homebrew)" - description "Sam Mallard - The Case of the Missing Swan (World) (Aftermarket) (Homebrew)" - rom ( name "Sam Mallard - The Case of the Missing Swan (World) (Aftermarket) (Homebrew).gb" size 1048576 crc 994a2edd sha1 0132f0311d8478d4f45b3b8e2728698570091d69 ) + name "Sam Mallard - The Case of the Missing Swan (World) (SGB Enhanced) (Aftermarket) (Unl)" + description "Sam Mallard - The Case of the Missing Swan (World) (SGB Enhanced) (Aftermarket) (Unl)" + rom ( name "Sam Mallard - The Case of the Missing Swan (World) (SGB Enhanced) (Aftermarket) (Unl).gb" size 1048576 crc 994a2edd sha1 0132f0311d8478d4f45b3b8e2728698570091d69 ) ) game ( @@ -30148,12 +31500,30 @@ game ( rom ( name "Shanghai Pocket (Japan) (SGB Enhanced).gb" size 262144 crc 6b8eff2c sha1 82fe97442aa625fd36cf865d82f78b07108ede7f ) ) +game ( + name "Shapeshifter, The (World) (Aftermarket) (Unl)" + description "Shapeshifter, The (World) (Aftermarket) (Unl)" + rom ( name "Shapeshifter, The (World) (Aftermarket) (Unl).gb" size 1048576 crc ef735794 sha1 179e69199f19b403b4c1a9675a3ee431ee570797 ) +) + game ( name "Shaq Fu (USA) (SGB Enhanced)" description "Shaq Fu (USA) (SGB Enhanced)" rom ( name "Shaq Fu (USA) (SGB Enhanced).gb" size 524288 crc 7ed43fe6 sha1 5e9e68d9235cf8149232b85fd6080ba8796cb85e ) ) +game ( + name "Shark Attack (World) (Aftermarket) (Unl)" + description "Shark Attack (World) (Aftermarket) (Unl)" + rom ( name "Shark Attack (World) (Aftermarket) (Unl).gb" size 262144 crc 3032025a sha1 6cc65bb719af53128bb04c9ee7c6abbf4ff1c3cf ) +) + +game ( + name "Sheep it Up (World) (Digital) (Aftermarket) (Unl)" + description "Sheep it Up (World) (Digital) (Aftermarket) (Unl)" + rom ( name "Sheep it Up (World) (Digital) (Aftermarket) (Unl).gb" size 32768 crc fa6de2e4 sha1 9ad365ed7d4e07041c0147831a9bb1c496ea0bc8 ) +) + game ( name "Shikinjou (Japan)" description "Shikinjou (Japan)" @@ -30221,21 +31591,21 @@ game ( ) game ( - name "Shock Lobster (World) (Aftermarket) (Homebrew)" - description "Shock Lobster (World) (Aftermarket) (Homebrew)" - rom ( name "Shock Lobster (World) (Aftermarket) (Homebrew).gb" size 32768 crc 7a0622e6 sha1 10c1816724cd6e332d2a5aeed4e546e7bd764ebf ) + name "Shock Lobster (World) (Aftermarket) (Unl)" + description "Shock Lobster (World) (Aftermarket) (Unl)" + rom ( name "Shock Lobster (World) (Aftermarket) (Unl).gb" size 32768 crc 7a0622e6 sha1 10c1816724cd6e332d2a5aeed4e546e7bd764ebf ) ) game ( - name "Shock Lobster (World) (v1.3) (Aftermarket) (Homebrew)" - description "Shock Lobster (World) (v1.3) (Aftermarket) (Homebrew)" - rom ( name "Shock Lobster (World) (v1.3) (Aftermarket) (Homebrew).gb" size 32768 crc 8f244e86 sha1 7b8c8a9ec4758c6880598b9d508bc5805293dd87 ) + name "Shock Lobster (World) (v1.3) (Aftermarket) (Unl)" + description "Shock Lobster (World) (v1.3) (Aftermarket) (Unl)" + rom ( name "Shock Lobster (World) (v1.3) (Aftermarket) (Unl).gb" size 32768 crc 8f244e86 sha1 7b8c8a9ec4758c6880598b9d508bc5805293dd87 ) ) game ( - name "Shootris (World) (Aftermarket) (Homebrew)" - description "Shootris (World) (Aftermarket) (Homebrew)" - rom ( name "Shootris (World) (Aftermarket) (Homebrew).gb" size 262144 crc 50180f64 sha1 5d978e6fc4bd5d9717d022360122458e95fffc29 ) + name "Shootris (World) (Aftermarket) (Unl)" + description "Shootris (World) (Aftermarket) (Unl)" + rom ( name "Shootris (World) (Aftermarket) (Unl).gb" size 262144 crc 50180f64 sha1 5d978e6fc4bd5d9717d022360122458e95fffc29 ) ) game ( @@ -30323,9 +31693,9 @@ game ( ) game ( - name "Sloth Story (World) (v1.0) (Aftermarket) (Homebrew)" - description "Sloth Story (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Sloth Story (World) (v1.0) (Aftermarket) (Homebrew).gb" size 262144 crc c873f232 sha1 369d2afec4ffb59d4f3a59ee684c5bfec0b34ff8 ) + name "Sloth Story (World) (Aftermarket) (Unl)" + description "Sloth Story (World) (Aftermarket) (Unl)" + rom ( name "Sloth Story (World) (Aftermarket) (Unl).gb" size 262144 crc c873f232 sha1 369d2afec4ffb59d4f3a59ee684c5bfec0b34ff8 ) ) game ( @@ -30335,15 +31705,15 @@ game ( ) game ( - name "SMARTCOM (Europe) (Unl)" - description "SMARTCOM (Europe) (Unl)" - rom ( name "SMARTCOM (Europe) (Unl).gb" size 262144 crc 1ef0abf1 sha1 a04bbf813bcd9b7e3af97d388ad77d25c1403831 ) + name "SmartCom (Europe) (Unl)" + description "SmartCom (Europe) (Unl)" + rom ( name "SmartCom (Europe) (Unl).gb" size 262144 crc 1ef0abf1 sha1 a04bbf813bcd9b7e3af97d388ad77d25c1403831 ) ) game ( name "Smurfs Nightmare, The (Europe) (En,Fr,De,Es)" description "Smurfs Nightmare, The (Europe) (En,Fr,De,Es)" - rom ( name "Smurfs Nightmare, The (Europe) (En,Fr,De,Es).gb" size 262144 crc 8ef938c4 sha1 efbc4bc9714393d5f493ad653fc1fa2180b40892 ) + rom ( name "Smurfs Nightmare, The (Europe) (En,Fr,De,Es).gb" size 262144 crc 8ef938c4 sha1 efbc4bc9714393d5f493ad653fc1fa2180b40892 flags verified ) ) game ( @@ -30365,21 +31735,21 @@ game ( ) game ( - name "Snail DX, The (World) (v1.0) (Aftermarket) (Homebrew)" - description "Snail DX, The (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Snail DX, The (World) (v1.0) (Aftermarket) (Homebrew).gb" size 262144 crc 1aecd096 sha1 8ce256d963a55badf71fd45047c173a74d76a92c ) + name "Snail, The (World) (v1.3) (Aftermarket) (Unl)" + description "Snail, The (World) (v1.3) (Aftermarket) (Unl)" + rom ( name "Snail, The (World) (v1.3) (Aftermarket) (Unl).gb" size 262144 crc 422a7b44 sha1 776f7578d747f935ebccda93d6487ffa4dc4bce3 ) ) game ( - name "Snail, The (World) (v1.3) (Aftermarket) (Homebrew)" - description "Snail, The (World) (v1.3) (Aftermarket) (Homebrew)" - rom ( name "Snail, The (World) (v1.3) (Aftermarket) (Homebrew).gb" size 262144 crc 422a7b44 sha1 776f7578d747f935ebccda93d6487ffa4dc4bce3 ) + name "Snakebird (World) (Aftermarket) (Unl)" + description "Snakebird (World) (Aftermarket) (Unl)" + rom ( name "Snakebird (World) (Aftermarket) (Unl).gb" size 131072 crc 4627f98e sha1 99cc82279d65b86b4366bf61db9bf67a78e051dc ) ) game ( - name "Snakebird (World) (Aftermarket) (Homebrew)" - description "Snakebird (World) (Aftermarket) (Homebrew)" - rom ( name "Snakebird (World) (Aftermarket) (Homebrew).gb" size 131072 crc 4627f98e sha1 99cc82279d65b86b4366bf61db9bf67a78e051dc ) + name "Snaky Pocket (World) (Aftermarket) (Unl)" + description "Snaky Pocket (World) (Aftermarket) (Unl)" + rom ( name "Snaky Pocket (World) (Aftermarket) (Unl).gb" size 32768 crc 7209370d sha1 f5eab31a499f33b3ae1f7b5b006dcca1df3ac2b9 ) ) game ( @@ -30406,12 +31776,6 @@ game ( rom ( name "Snoopy's Magic Show (USA, Europe).gb" size 65536 crc 2b7a5034 sha1 bc21fb3aa1a58e2aef30fabe103b2e5bec02b535 flags verified ) ) -game ( - name "Snooze (World) (Aftermarket) (Homebrew)" - description "Snooze (World) (Aftermarket) (Homebrew)" - rom ( name "Snooze (World) (Aftermarket) (Homebrew).gb" size 262144 crc b246095f sha1 b7fdcc006c9c06dd391ee26d44b278d9d3793f6d ) -) - game ( name "Snow Bros. Jr. (Japan)" description "Snow Bros. Jr. (Japan)" @@ -30497,9 +31861,27 @@ game ( ) game ( - name "Sonic 6 (Unknown) (En) (Pirate)" - description "Sonic 6 (Unknown) (En) (Pirate)" - rom ( name "Sonic 6 (Unknown) (En) (Pirate).gb" size 524288 crc aa4e9379 sha1 5f70ee1a1265536c6ed3657bfd5e54516add287d ) + name "Song of Morus - Gala of Battle (World) (En,Ja) (Aftermarket) (Unl)" + description "Song of Morus - Gala of Battle (World) (En,Ja) (Aftermarket) (Unl)" + rom ( name "Song of Morus - Gala of Battle (World) (En,Ja) (Aftermarket) (Unl).gb" size 262144 crc 665ad70a sha1 c5b6eb610caa2213d8db7ab204bad44d60f7d63a ) +) + +game ( + name "Song of Morus - Ghostly Night (World) (2023-05-20) (Aftermarket) (Unl)" + description "Song of Morus - Ghostly Night (World) (2023-05-20) (Aftermarket) (Unl)" + rom ( name "Song of Morus - Ghostly Night (World) (2023-05-20) (Aftermarket) (Unl).gb" size 262144 crc feed93e0 sha1 721d78d4ef167acfcc00baf909db4c94d522d681 ) +) + +game ( + name "Song of Morus - Ghostly Night (World) (2023-06-08) (Aftermarket) (Unl)" + description "Song of Morus - Ghostly Night (World) (2023-06-08) (Aftermarket) (Unl)" + rom ( name "Song of Morus - Ghostly Night (World) (2023-06-08) (Aftermarket) (Unl).gb" size 262144 crc 6547e5c8 sha1 53a42f45b7ed368d7af9d41f2442fe463c26e545 ) +) + +game ( + name "Sonic 6 (USA) (Pirate)" + description "Sonic 6 (USA) (Pirate)" + rom ( name "Sonic 6 (USA) (Pirate).gb" size 524288 crc aa4e9379 sha1 5f70ee1a1265536c6ed3657bfd5e54516add287d ) ) game ( @@ -30556,6 +31938,12 @@ game ( rom ( name "Space Invaders (Europe) (Beta) (SGB Enhanced).gb" size 131072 crc 2d03dc38 sha1 6a2af41de10dbf6496b18963d904cc41d04bb970 ) ) +game ( + name "Space Trouble (World) (Proto) (Aftermarket) (Unl)" + description "Space Trouble (World) (Proto) (Aftermarket) (Unl)" + rom ( name "Space Trouble (World) (Proto) (Aftermarket) (Unl).gb" size 524288 crc f015931c sha1 ec7bc27387d4d2ac01127bc24e1adf45b6ebc936 ) +) + game ( name "Spanky's Quest (Europe)" description "Spanky's Quest (Europe)" @@ -30581,9 +31969,9 @@ game ( ) game ( - name "Speedball 2 - Brutal Deluxe (Japan) (En)" - description "Speedball 2 - Brutal Deluxe (Japan) (En)" - rom ( name "Speedball 2 - Brutal Deluxe (Japan) (En).gb" size 131072 crc d0e0116f sha1 2b9bc1e7eadf90611112463053a9915c8159c3bc ) + name "Speedball 2 - Brutal Deluxe (Japan) (En) (Possible Proto)" + description "Speedball 2 - Brutal Deluxe (Japan) (En) (Possible Proto)" + rom ( name "Speedball 2 - Brutal Deluxe (Japan) (En) (Possible Proto).gb" size 131072 crc d0e0116f sha1 2b9bc1e7eadf90611112463053a9915c8159c3bc ) ) game ( @@ -30622,6 +32010,12 @@ game ( rom ( name "Spider-Man 3 - Invasion of the Spider-Slayers (USA, Europe) (Beta 2) (1993-04-11).gb" size 131072 crc bf2d1f10 sha1 34740dc60663ef33c42573a26e7b207f2cfe4a16 ) ) +game ( + name "Spiky Harold (World) (Aftermarket) (Unl)" + description "Spiky Harold (World) (Aftermarket) (Unl)" + rom ( name "Spiky Harold (World) (Aftermarket) (Unl).gb" size 524288 crc 2ac1b945 sha1 b8f37a64524bde4c2b6e9a1938ed6e5c0a5aad7c ) +) + game ( name "Spirit of F-1, The (Europe)" description "Spirit of F-1, The (Europe)" @@ -30821,9 +32215,9 @@ game ( ) game ( - name "StarFox - Grounded (World) (Aftermarket) (Homebrew)" - description "StarFox - Grounded (World) (Aftermarket) (Homebrew)" - rom ( name "StarFox - Grounded (World) (Aftermarket) (Homebrew).gb" size 524288 crc 82658661 sha1 dd45b0e3f346ce33668d49092b29a44597686061 ) + name "Stardiver (World) (Aftermarket) (Unl)" + description "Stardiver (World) (Aftermarket) (Unl)" + rom ( name "Stardiver (World) (Aftermarket) (Unl).gb" size 1048576 crc 25ff97f7 sha1 d609b8de2c7a61b7281fec5c761e3504aa4d94e9 ) ) game ( @@ -30899,9 +32293,9 @@ game ( ) game ( - name "Super 69 in 1 (World) (Unl)" - description "Super 69 in 1 (World) (Unl)" - rom ( name "Super 69 in 1 (World) (Unl).gb" size 32768 crc 9cf64fb6 sha1 91e7012c1eeeea280117c245b031400d060bd978 ) + name "Super 69 in 1 (Europe) (Unl)" + description "Super 69 in 1 (Europe) (Unl)" + rom ( name "Super 69 in 1 (Europe) (Unl).gb" size 32768 crc 9cf64fb6 sha1 91e7012c1eeeea280117c245b031400d060bd978 ) ) game ( @@ -31007,9 +32401,9 @@ game ( ) game ( - name "Super Covid Go Get Biscuits Adventure (World) (Aftermarket) (Homebrew)" - description "Super Covid Go Get Biscuits Adventure (World) (Aftermarket) (Homebrew)" - rom ( name "Super Covid Go Get Biscuits Adventure (World) (Aftermarket) (Homebrew).gb" size 262144 crc 51946e8d sha1 cac4917d56da02cf88ba68e0c5189a18c2c234ac ) + name "Super Covid Go Get Biscuits Adventure (World) (Aftermarket) (Unl)" + description "Super Covid Go Get Biscuits Adventure (World) (Aftermarket) (Unl)" + rom ( name "Super Covid Go Get Biscuits Adventure (World) (Aftermarket) (Unl).gb" size 262144 crc 51946e8d sha1 cac4917d56da02cf88ba68e0c5189a18c2c234ac ) ) game ( @@ -31042,12 +32436,6 @@ game ( rom ( name "Super Hunchback (USA).gb" size 131072 crc 1a45706e sha1 9d53fbfeeec5a1a8352177c157ce615621c4b30c ) ) -game ( - name "Super Imposter Bros. (World) (Aftermarket) (Homebrew)" - description "Super Imposter Bros. (World) (Aftermarket) (Homebrew)" - rom ( name "Super Imposter Bros. (World) (Aftermarket) (Homebrew).gb" size 1048576 crc a38d702f sha1 301f93da4e5b0cd8dc3f1bf3e66e38176b8a909b ) -) - game ( name "Super James Pond (Europe)" description "Super James Pond (Europe)" @@ -31211,9 +32599,9 @@ game ( ) game ( - name "Sushi Gun (World) (Aftermarket) (Homebrew)" - description "Sushi Gun (World) (Aftermarket) (Homebrew)" - rom ( name "Sushi Gun (World) (Aftermarket) (Homebrew).gb" size 262144 crc a9d405d6 sha1 c075856939d4fe3cd250083b527b3e09be70052d ) + name "Sushi Gun (World) (Aftermarket) (Unl)" + description "Sushi Gun (World) (Aftermarket) (Unl)" + rom ( name "Sushi Gun (World) (Aftermarket) (Unl).gb" size 262144 crc a9d405d6 sha1 c075856939d4fe3cd250083b527b3e09be70052d ) ) game ( @@ -31241,9 +32629,9 @@ game ( ) game ( - name "SWAPLATFORMER (World) (Aftermarket) (Homebrew)" - description "SWAPLATFORMER (World) (Aftermarket) (Homebrew)" - rom ( name "SWAPLATFORMER (World) (Aftermarket) (Homebrew).gb" size 1048576 crc babe7935 sha1 3df0c37862b7c391a0d091a55db0d305341529c2 ) + name "Swaplatformer (World) (Aftermarket) (Unl)" + description "Swaplatformer (World) (Aftermarket) (Unl)" + rom ( name "Swaplatformer (World) (Aftermarket) (Unl).gb" size 1048576 crc babe7935 sha1 3df0c37862b7c391a0d091a55db0d305341529c2 ) ) game ( @@ -31342,6 +32730,12 @@ game ( rom ( name "Takahashi Meijin no Bouken-jima III (Japan).gb" size 262144 crc f8fc0b41 sha1 e3fe857a1b7f00a6f7862d7dd401063f98fd0cb6 ) ) +game ( + name "Take It Racing 2 (World) (Demo) (Aftermarket) (Unl)" + description "Take It Racing 2 (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Take It Racing 2 (World) (Demo) (Aftermarket) (Unl).gb" size 1048576 crc 5898c134 sha1 bd3468395deb0009b190d0b5d487962ae65adbee ) +) + game ( name "Takeda Nobuhiro no Ace Striker (Japan)" description "Takeda Nobuhiro no Ace Striker (Japan)" @@ -31415,9 +32809,9 @@ game ( ) game ( - name "Tech and Blood (World) (Aftermarket) (Homebrew)" - description "Tech and Blood (World) (Aftermarket) (Homebrew)" - rom ( name "Tech and Blood (World) (Aftermarket) (Homebrew).gb" size 262144 crc 3da2a358 sha1 40a00fce49b16cb36793df30e5156e5bf3e47778 ) + name "Tech and Blood (World) (Aftermarket) (Unl)" + description "Tech and Blood (World) (Aftermarket) (Unl)" + rom ( name "Tech and Blood (World) (Aftermarket) (Unl).gb" size 262144 crc 3da2a358 sha1 40a00fce49b16cb36793df30e5156e5bf3e47778 ) ) game ( @@ -31462,6 +32856,18 @@ game ( rom ( name "Teenage Mutant Ninja Turtles (Japan).gb" size 131072 crc 74078236 sha1 1f17169d70365831537376beb2477374649f830b ) ) +game ( + name "Teenage Mutant Ninja Turtles (Japan) (Cowabunga Collection, The)" + description "Teenage Mutant Ninja Turtles (Japan) (Cowabunga Collection, The)" + rom ( name "Teenage Mutant Ninja Turtles (Japan) (Cowabunga Collection, The).gb" size 131072 crc b3f6eec2 sha1 8e5398a96523b83da1ed0600f57a774cde7729a7 ) +) + +game ( + name "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA) (Cowabunga Collection, The)" + description "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA) (Cowabunga Collection, The)" + rom ( name "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA) (Cowabunga Collection, The).gb" size 131072 crc 3b11a875 sha1 d20ba3c691a484bfcc80331e11bb76f652b4290c ) +) + game ( name "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA)" description "Teenage Mutant Ninja Turtles - Fall of the Foot Clan (USA)" @@ -31480,6 +32886,18 @@ game ( rom ( name "Teenage Mutant Ninja Turtles 2 (Japan) (En) (Beta) (1991-05-20).gb" size 262144 crc 64a667a3 sha1 864a686f74a22ff8d27da511b08bbfbef1bd563d ) ) +game ( + name "Teenage Mutant Ninja Turtles 2 (Japan) (Cowabunga Collection, The)" + description "Teenage Mutant Ninja Turtles 2 (Japan) (Cowabunga Collection, The)" + rom ( name "Teenage Mutant Ninja Turtles 2 (Japan) (Cowabunga Collection, The).gb" size 262144 crc 3e83abd3 sha1 a05025f1840f27d4a12574fd6ee60e0b42c68ed8 ) +) + +game ( + name "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan) (Cowabunga Collection, The)" + description "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan) (Cowabunga Collection, The)" + rom ( name "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan) (Cowabunga Collection, The).gb" size 131072 crc cc91ab3b sha1 fc94ee81585583a39542b31a80c05f176da8b9e2 ) +) + game ( name "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan)" description "Teenage Mutant Ninja Turtles 3 - Turtles Kikiippatsu (Japan)" @@ -31498,6 +32916,18 @@ game ( rom ( name "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA) (Beta).gb" size 262144 crc ee25b752 sha1 7fd1df99ed3bc088c737f0ef8b7f0caa95d73b65 ) ) +game ( + name "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA) (Cowabunga Collection, The)" + description "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA) (Cowabunga Collection, The)" + rom ( name "Teenage Mutant Ninja Turtles II - Back from the Sewers (USA) (Cowabunga Collection, The).gb" size 262144 crc 78b901d5 sha1 41c8ed509ec914e50f7e28601e0f6e5736de90fb ) +) + +game ( + name "Teenage Mutant Ninja Turtles III - Radical Rescue (USA) (Cowabunga Collection, The)" + description "Teenage Mutant Ninja Turtles III - Radical Rescue (USA) (Cowabunga Collection, The)" + rom ( name "Teenage Mutant Ninja Turtles III - Radical Rescue (USA) (Cowabunga Collection, The).gb" size 131072 crc 3a4d4b09 sha1 ade406d5ec0f3253c4d3be3b7507e027098f04a3 ) +) + game ( name "Teenage Mutant Ninja Turtles III - Radical Rescue (USA)" description "Teenage Mutant Ninja Turtles III - Radical Rescue (USA)" @@ -31637,15 +33067,21 @@ game ( ) game ( - name "There's Nothing To Do In This Town (World) (v1.0) (Aftermarket) (Homebrew)" - description "There's Nothing To Do In This Town (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "There's Nothing To Do In This Town (World) (v1.0) (Aftermarket) (Homebrew).gb" size 1048576 crc 173b549a sha1 e000fbecda9ea6bbbd0c0370cf8c3faaa54bf64e ) + name "There's Nothing to Do in This Town (World) (Aftermarket) (Unl)" + description "There's Nothing to Do in This Town (World) (Aftermarket) (Unl)" + rom ( name "There's Nothing to Do in This Town (World) (Aftermarket) (Unl).gb" size 1048576 crc 173b549a sha1 e000fbecda9ea6bbbd0c0370cf8c3faaa54bf64e ) ) game ( - name "Thin Ice Rescue, The (World) (Aftermarket) (Homebrew)" - description "Thin Ice Rescue, The (World) (Aftermarket) (Homebrew)" - rom ( name "Thin Ice Rescue, The (World) (Aftermarket) (Homebrew).gb" size 32768 crc 3e0483d6 sha1 b789ced0fe26785e7bce765a9d6ee783f9d967d8 ) + name "Thin Ice Rescue, The (World) (Aftermarket) (Unl)" + description "Thin Ice Rescue, The (World) (Aftermarket) (Unl)" + rom ( name "Thin Ice Rescue, The (World) (Aftermarket) (Unl).gb" size 32768 crc 3e0483d6 sha1 b789ced0fe26785e7bce765a9d6ee783f9d967d8 ) +) + +game ( + name "TimberMan (World) (Aftermarket) (Unl)" + description "TimberMan (World) (Aftermarket) (Unl)" + rom ( name "TimberMan (World) (Aftermarket) (Unl).gb" size 32768 crc e0b8459c sha1 e3f4b4c4816cc0dda2885519f1386385e6a5e817 ) ) game ( @@ -31672,18 +33108,6 @@ game ( rom ( name "Tintin in Tibet (Europe) (En,Es,It,Sv) (Beta) (SGB Enhanced).gb" size 262144 crc 68b7fcf2 sha1 63070514f0a692cef70e9344ca0a973f6af510c9 ) ) -game ( - name "Tiny Grasshopper Goes Away (World) (v1.4) (Aftermarket) (Homebrew)" - description "Tiny Grasshopper Goes Away (World) (v1.4) (Aftermarket) (Homebrew)" - rom ( name "Tiny Grasshopper Goes Away (World) (v1.4) (Aftermarket) (Homebrew).gb" size 262144 crc af13e718 sha1 307e51664db2101755b6c617f3d81ee58676c485 ) -) - -game ( - name "Tiny Grasshopper Goes Away (World) (v1.2) (Aftermarket) (Homebrew)" - description "Tiny Grasshopper Goes Away (World) (v1.2) (Aftermarket) (Homebrew)" - rom ( name "Tiny Grasshopper Goes Away (World) (v1.2) (Aftermarket) (Homebrew).gb" size 262144 crc 0518f5aa sha1 85e5cd0cf7a6cc4a5946c93fa8665235a686e554 ) -) - game ( name "Tiny Toon Adventures (Japan)" description "Tiny Toon Adventures (Japan)" @@ -31751,9 +33175,9 @@ game ( ) game ( - name "Tobu Tobu Girl (World) (Aftermarket) (Homebrew)" - description "Tobu Tobu Girl (World) (Aftermarket) (Homebrew)" - rom ( name "Tobu Tobu Girl (World) (Aftermarket) (Homebrew).gb" size 262144 crc ed12be6c sha1 8a8f3c1f21f903ea5a7df8fc8b0a6aa5a602e150 ) + name "Tobu Tobu Girl (World) (Aftermarket) (Unl)" + description "Tobu Tobu Girl (World) (Aftermarket) (Unl)" + rom ( name "Tobu Tobu Girl (World) (Aftermarket) (Unl).gb" size 262144 crc ed12be6c sha1 8a8f3c1f21f903ea5a7df8fc8b0a6aa5a602e150 ) ) game ( @@ -31919,15 +33343,33 @@ game ( ) game ( - name "Trax (USA, Europe)" - description "Trax (USA, Europe)" - rom ( name "Trax (USA, Europe).gb" size 131072 crc 4a38be7d sha1 3f3a31ed7e47319c5815dd6e31ca27a52377423c ) + name "Traumatarium (World) (Demo) (2021-12-09) (Aftermarket) (Unl)" + description "Traumatarium (World) (Demo) (2021-12-09) (Aftermarket) (Unl)" + rom ( name "Traumatarium (World) (Demo) (2021-12-09) (Aftermarket) (Unl).gb" size 2097152 crc 15afd765 sha1 c12e603492f8bcfffd28dd4733c7bc445c507642 ) ) game ( - name "Treasure Island (World) (Aftermarket) (Homebrew)" - description "Treasure Island (World) (Aftermarket) (Homebrew)" - rom ( name "Treasure Island (World) (Aftermarket) (Homebrew).gb" size 262144 crc cbdec393 sha1 adeaba2723d286d143e0987f51ce9c8ad2f5e839 ) + name "Traumatarium (World) (Demo) (2022-06-18) (Aftermarket) (Unl)" + description "Traumatarium (World) (Demo) (2022-06-18) (Aftermarket) (Unl)" + rom ( name "Traumatarium (World) (Demo) (2022-06-18) (Aftermarket) (Unl).gb" size 2097152 crc e1bdf67f sha1 ba492778121622b5288d4188edc344aa41aa6803 ) +) + +game ( + name "Traumatarium (World) (Demo) (2022-03-13) (Aftermarket) (Unl)" + description "Traumatarium (World) (Demo) (2022-03-13) (Aftermarket) (Unl)" + rom ( name "Traumatarium (World) (Demo) (2022-03-13) (Aftermarket) (Unl).gb" size 1048576 crc 42bb7dab sha1 70fded7ce1edc54de85b020460f779feb9bdbc01 ) +) + +game ( + name "Trax (USA, Europe)" + description "Trax (USA, Europe)" + rom ( name "Trax (USA, Europe).gb" size 131072 crc 4a38be7d sha1 3f3a31ed7e47319c5815dd6e31ca27a52377423c flags verified ) +) + +game ( + name "Treasure Island (World) (Aftermarket) (Unl)" + description "Treasure Island (World) (Aftermarket) (Unl)" + rom ( name "Treasure Island (World) (Aftermarket) (Unl).gb" size 262144 crc cbdec393 sha1 adeaba2723d286d143e0987f51ce9c8ad2f5e839 ) ) game ( @@ -31954,12 +33396,6 @@ game ( rom ( name "Triumph (USA) (Proto).gb" size 131072 crc 746159b2 sha1 90a40fc94709a3ec6945281bde2644d91bef28b5 ) ) -game ( - name "Trouble City - Pocket Mission (World) (Aftermarket) (Homebrew)" - description "Trouble City - Pocket Mission (World) (Aftermarket) (Homebrew)" - rom ( name "Trouble City - Pocket Mission (World) (Aftermarket) (Homebrew).gb" size 524288 crc 4b9143ad sha1 0e51e398d44aaad74a7c622f7818b56a3b34db56 ) -) - game ( name "True Lies (USA, Europe)" description "True Lies (USA, Europe)" @@ -32176,12 +33612,6 @@ game ( rom ( name "Undercover Cops Gaiden - Hakaishin Garumaa (Japan).gb" size 262144 crc b7af37f5 sha1 e391ea099ce371eef858d57e6c2da63a25944472 ) ) -game ( - name "Ungrateful Son, The (World) (Aftermarket) (Homebrew)" - description "Ungrateful Son, The (World) (Aftermarket) (Homebrew)" - rom ( name "Ungrateful Son, The (World) (Aftermarket) (Homebrew).gb" size 262144 crc 977b54f4 sha1 016dde406896d827dcad682d40b52d0e9eeefa88 ) -) - game ( name "Universal Soldier (USA, Europe)" description "Universal Soldier (USA, Europe)" @@ -32224,6 +33654,12 @@ game ( rom ( name "V-Rally - Championship Edition (Europe) (En,Fr,De).gb" size 262144 crc d149652b sha1 67d2a6e41b6a1d8372808535ac8c8222d7c53480 flags verified ) ) +game ( + name "Vampire Night Shift (World) (Aftermarket) (Unl)" + description "Vampire Night Shift (World) (Aftermarket) (Unl)" + rom ( name "Vampire Night Shift (World) (Aftermarket) (Unl).gb" size 262144 crc 88acbc1a sha1 ef617803c2cdb14cfe3b3b2111aa239a3744e29e ) +) + game ( name "Vattle Giuce (Japan)" description "Vattle Giuce (Japan)" @@ -32279,9 +33715,9 @@ game ( ) game ( - name "Waifu Clicker (World) (Aftermarket) (Homebrew)" - description "Waifu Clicker (World) (Aftermarket) (Homebrew)" - rom ( name "Waifu Clicker (World) (Aftermarket) (Homebrew).gb" size 65536 crc 155f85dc sha1 bb571ed69c3a33e45ba33fbb03a066ba98ae0b20 ) + name "Waifu Clicker (World) (Aftermarket) (Unl)" + description "Waifu Clicker (World) (Aftermarket) (Unl)" + rom ( name "Waifu Clicker (World) (Aftermarket) (Unl).gb" size 65536 crc 155f85dc sha1 bb571ed69c3a33e45ba33fbb03a066ba98ae0b20 ) ) game ( @@ -32302,24 +33738,6 @@ game ( rom ( name "Wario Land II (USA, Europe) (SGB Enhanced).gb" size 1048576 crc 9c54358d sha1 c65820b2e52d00e6ce60e0a432fab002fec4386f flags verified ) ) -game ( - name "Warp Coin Catastrophe, The (World) (v1.1) (Aftermarket) (Homebrew)" - description "Warp Coin Catastrophe, The (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Warp Coin Catastrophe, The (World) (v1.1) (Aftermarket) (Homebrew).gb" size 1048576 crc a381c914 sha1 adf37c5d2f706743b2a4946378df49ed19212039 ) -) - -game ( - name "Warp Coin Catastrophe, The (World) (v1.0) (Aftermarket) (Homebrew)" - description "Warp Coin Catastrophe, The (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Warp Coin Catastrophe, The (World) (v1.0) (Aftermarket) (Homebrew).gb" size 1048576 crc 1bfe1bf9 sha1 fae12dbbb75ae024e96a7ee21ad4077fdb5ed9a1 ) -) - -game ( - name "Warp Coin Catastrophe, The (World) (v1.1.2) (Aftermarket) (Homebrew)" - description "Warp Coin Catastrophe, The (World) (v1.1.2) (Aftermarket) (Homebrew)" - rom ( name "Warp Coin Catastrophe, The (World) (v1.1.2) (Aftermarket) (Homebrew).gb" size 1048576 crc 5519c167 sha1 04a53af6a77b884af91f8047d70fc0331bf23913 ) -) - game ( name "Waterworld (Europe)" description "Waterworld (Europe)" @@ -32362,6 +33780,12 @@ game ( rom ( name "Welcome Nakayoshi Park (Japan).gb" size 262144 crc f6e2baae sha1 8779a1557ba0de3c5c8b770413f30bd31717b2ef ) ) +game ( + name "What Friends Are For (World) (Aftermarket) (Unl)" + description "What Friends Are For (World) (Aftermarket) (Unl)" + rom ( name "What Friends Are For (World) (Aftermarket) (Unl).gb" size 262144 crc cbed3dd6 sha1 58538084a964f779c2f756fbe732656f3f7bef66 ) +) + game ( name "Wheel of Fortune (USA)" description "Wheel of Fortune (USA)" @@ -32398,6 +33822,12 @@ game ( rom ( name "Wily & Right no Rockboard - That's Paradise (Japan) (Proto).gb" size 262144 crc af84dc97 sha1 cc917f113c5cdd1afc3340feb8bf2094d0902cec ) ) +game ( + name "Windows93 Adventure (World) (Aftermarket) (Unl)" + description "Windows93 Adventure (World) (Aftermarket) (Unl)" + rom ( name "Windows93 Adventure (World) (Aftermarket) (Unl).gb" size 1048576 crc e1ad0b6f sha1 3ad7327f6f94976c3d12054cf6deb2666ba9fa66 ) +) + game ( name "Winner's Horse (Japan)" description "Winner's Horse (Japan)" @@ -32423,9 +33853,9 @@ game ( ) game ( - name "Wizard of Wor (World) (Aftermarket) (Homebrew)" - description "Wizard of Wor (World) (Aftermarket) (Homebrew)" - rom ( name "Wizard of Wor (World) (Aftermarket) (Homebrew).gb" size 524288 crc bfb1563e sha1 108eefa154412e3422dce4e63bf34f5826ec1baa ) + name "Wizard of Wor (World) (Aftermarket) (Unl)" + description "Wizard of Wor (World) (Aftermarket) (Unl)" + rom ( name "Wizard of Wor (World) (Aftermarket) (Unl).gb" size 524288 crc bfb1563e sha1 108eefa154412e3422dce4e63bf34f5826ec1baa ) ) game ( @@ -32453,9 +33883,9 @@ game ( ) game ( - name "Woolball's Backyard (World) (Aftermarket) (Homebrew)" - description "Woolball's Backyard (World) (Aftermarket) (Homebrew)" - rom ( name "Woolball's Backyard (World) (Aftermarket) (Homebrew).gb" size 65536 crc 69e26eb6 sha1 28795c4b829440549b3ac2afe3282d85a439f7d7 ) + name "Woolball's Backyard (World) (Aftermarket) (Unl)" + description "Woolball's Backyard (World) (Aftermarket) (Unl)" + rom ( name "Woolball's Backyard (World) (Aftermarket) (Unl).gb" size 65536 crc 69e26eb6 sha1 28795c4b829440549b3ac2afe3282d85a439f7d7 ) ) game ( @@ -32668,6 +34098,12 @@ game ( rom ( name "Xenon 2 - Megablast (Japan).gb" size 131072 crc 2feb70d2 sha1 6b2f009b7a443e5ead48a2864bfb1d29096ed6a0 ) ) +game ( + name "Xin Nushen Zhuansheng Waizhuan - Zuihou de Shengjing (Taiwan) (Pirate)" + description "Xin Nushen Zhuansheng Waizhuan - Zuihou de Shengjing (Taiwan) (Pirate)" + rom ( name "Xin Nushen Zhuansheng Waizhuan - Zuihou de Shengjing (Taiwan) (Pirate).gb" size 524288 crc 2298585c sha1 f33091c0bfd840e0ce4c4f99c463cfb92f823a64 ) +) + game ( name "Yakuman (Japan)" description "Yakuman (Japan)" @@ -32687,27 +34123,21 @@ game ( ) game ( - name "Year After, The (USA) (Aftermarket) (Homebrew)" - description "Year After, The (USA) (Aftermarket) (Homebrew)" - rom ( name "Year After, The (USA) (Aftermarket) (Homebrew).gb" size 1048576 crc 4e463a1a sha1 5d84f53f38aa24f54a6f897ca69ffc5d978805af ) + name "Year After, The (World) (En) (Proto) (Aftermarket) (Unl)" + description "Year After, The (World) (En) (Proto) (Aftermarket) (Unl)" + rom ( name "Year After, The (World) (En) (Proto) (Aftermarket) (Unl).gb" size 1048576 crc 4e463a1a sha1 5d84f53f38aa24f54a6f897ca69ffc5d978805af ) ) game ( - name "Year After, The (World) (Beta) (Aftermarket) (Homebrew)" - description "Year After, The (World) (Beta) (Aftermarket) (Homebrew)" - rom ( name "Year After, The (World) (Beta) (Aftermarket) (Homebrew).gb" size 1048576 crc f15351c8 sha1 a78ff2eef780287bbdc37df122cfc1c504526662 ) + name "Year After, The (World) (Fr) (Proto) (Aftermarket) (Unl)" + description "Year After, The (World) (Fr) (Proto) (Aftermarket) (Unl)" + rom ( name "Year After, The (World) (Fr) (Proto) (Aftermarket) (Unl).gb" size 1048576 crc fbc50ee8 sha1 52c27e64fb37412c97a53d5dde52c3803fd1e4f7 ) ) game ( - name "Year After, The (World) (Pt) (Beta) (Aftermarket) (Homebrew)" - description "Year After, The (World) (Pt) (Beta) (Aftermarket) (Homebrew)" - rom ( name "Year After, The (World) (Pt) (Beta) (Aftermarket) (Homebrew).gb" size 1048576 crc b70c1c7f sha1 ce25cdf6a6264586423e76e34dc42779d39a1cb1 ) -) - -game ( - name "Year After, The (World) (Fr) (Beta) (Aftermarket) (Homebrew)" - description "Year After, The (World) (Fr) (Beta) (Aftermarket) (Homebrew)" - rom ( name "Year After, The (World) (Fr) (Beta) (Aftermarket) (Homebrew).gb" size 1048576 crc fbc50ee8 sha1 52c27e64fb37412c97a53d5dde52c3803fd1e4f7 ) + name "Yelu Wangzi (Prince Yeh Rude) (Taiwan) (En) (Unl)" + description "Yelu Wangzi (Prince Yeh Rude) (Taiwan) (En) (Unl)" + rom ( name "Yelu Wangzi (Prince Yeh Rude) (Taiwan) (En) (Unl).gb" size 65536 crc 76ab9719 sha1 e4a762ef26a40fb88b4e89b839da8baa6e06b051 ) ) game ( @@ -32795,9 +34225,15 @@ game ( ) game ( - name "Yuuto Ichika Makes Friends (World) (Aftermarket) (Homebrew)" - description "Yuuto Ichika Makes Friends (World) (Aftermarket) (Homebrew)" - rom ( name "Yuuto Ichika Makes Friends (World) (Aftermarket) (Homebrew).gb" size 524288 crc 8a667058 sha1 e765d6915f543a5a65e8be440b3f29eb674a5448 ) + name "Yuuto Ichika Makes Friends (World) (En,Ja) (Aftermarket) (Unl)" + description "Yuuto Ichika Makes Friends (World) (En,Ja) (Aftermarket) (Unl)" + rom ( name "Yuuto Ichika Makes Friends (World) (En,Ja) (Aftermarket) (Unl).gb" size 524288 crc 8a667058 sha1 e765d6915f543a5a65e8be440b3f29eb674a5448 ) +) + +game ( + name "Zagan Warrior (World) (Aftermarket) (Unl)" + description "Zagan Warrior (World) (Aftermarket) (Unl)" + rom ( name "Zagan Warrior (World) (Aftermarket) (Unl).gb" size 262144 crc 97fe7a94 sha1 88f76297a4ccf0e3a5ba16ca15237c88346c134a ) ) game ( @@ -32806,6 +34242,12 @@ game ( rom ( name "ZAS (Europe) (Proto).gb" size 131072 crc ae282077 sha1 a480d3a205f4c6fe7da41637180459fb2cff9139 ) ) +game ( + name "Zelda - Majora's Mask (World) (v1.1) (Demo) (Aftermarket) (Unl)" + description "Zelda - Majora's Mask (World) (v1.1) (Demo) (Aftermarket) (Unl)" + rom ( name "Zelda - Majora's Mask (World) (v1.1) (Demo) (Aftermarket) (Unl).gb" size 524288 crc f86c2766 sha1 ee86a28cf271be43739e406135e4d8bd4edf7686 ) +) + game ( name "Zelda no Densetsu - Yume o Miru Shima (Japan)" description "Zelda no Densetsu - Yume o Miru Shima (Japan)" @@ -32818,6 +34260,18 @@ game ( rom ( name "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev 1).gb" size 524288 crc ea20b82a sha1 80f5d111c7e2d79d39f6c25a37b54c3196d2bd12 flags verified ) ) +game ( + name "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev 1) (Demo) (Special Version)" + description "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev 1) (Demo) (Special Version)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima (Japan) (Rev 1) (Demo) (Special Version).gb" size 524288 crc bcc0199a sha1 5fc7b8185096c4203536e0d8a302064e63511086 ) +) + +game ( + name "Zelda's Adventure (World) (v1.3.0) (Aftermarket) (Unl)" + description "Zelda's Adventure (World) (v1.3.0) (Aftermarket) (Unl)" + rom ( name "Zelda's Adventure (World) (v1.3.0) (Aftermarket) (Unl).gb" size 2097152 crc 0b10adaf sha1 12f9ba0a4673dd2f59ba38e636332333a199dea5 ) +) + game ( name "Zen - Intergalactic Ninja (Europe)" description "Zen - Intergalactic Ninja (Europe)" @@ -32897,16 +34351,22 @@ game ( ) game ( - name "Zuigao Jimi - Top Secret (Taiwan) (Unl)" - description "Zuigao Jimi - Top Secret (Taiwan) (Unl)" - rom ( name "Zuigao Jimi - Top Secret (Taiwan) (Unl).gb" size 65536 crc f5f8d0b3 sha1 be706d1b46fa1de966f0b3b08e85399177eb148c ) + name "Zuigao Jimi (Top Secret) (Taiwan) (Multicart Rip) (Unl)" + description "Zuigao Jimi (Top Secret) (Taiwan) (Multicart Rip) (Unl)" + rom ( name "Zuigao Jimi (Top Secret) (Taiwan) (Multicart Rip) (Unl).gb" size 65536 crc f5f8d0b3 sha1 be706d1b46fa1de966f0b3b08e85399177eb148c ) +) + +game ( + name "Zuigao Jimi (Top Secret) (Taiwan) (Unl)" + description "Zuigao Jimi (Top Secret) (Taiwan) (Unl)" + rom ( name "Zuigao Jimi (Top Secret) (Taiwan) (Unl).gb" size 65536 crc 46402abe sha1 7afcc6dd82bb236f1ebe01c9b5ccad4d713ccbcf ) ) clrmamepro ( name "Nintendo - Game Boy Color" description "Nintendo - Game Boy Color" - version 20220829-075630 - author "akubi, Arctic Circle System, Aringon, Bent, BigFred, BitLooter, C. V. Reynolds, chillerecke, coraz, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, Flashfire42, foxe, fuzzball, Hiccup, hking0036, InternalLoss, kazumi213, Lesserkuma, Madeline, Money_114, NGEfreak, nnssxx, norkmetnoil577, NovaAurora, omonim2007, PPLToast, relax, Rifu, sCZther, SonGoku, Tauwasser, togemet2, UnlockerPT, Whovian9369, xuom2, zg" + version 20240107-011427 + author "akubi, Arctic Circle System, Aringon, baldjared, Bent, BigFred, bikerspade, BitLooter, C. V. Reynolds, chillerecke, coraz, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, Flashfire42, foxe, fuzzball, Gefflon, gordonj, halftheisland, Hiccup, hking0036, InternalLoss, Just001Kim, kazumi213, Lesserkuma, Madeline, Money_114, NESBrew12, NGEfreak, nnssxx, norkmetnoil577, NovaAurora, omonim2007, PPLToast, Psychofox11, rarenight, relax, Rifu, sCZther, SonGoku, Tauwasser, togemet2, UnlockerPT, Whovian9369, xprism, xuom2, zg" homepage No-Intro url "https://www.no-intro.org" forcenodump required @@ -33006,6 +34466,108 @@ game ( rom ( name "1942 (USA, Europe).gbc" size 1048576 crc 87431672 sha1 d960e951b18d07e79d046313df49c18313664224 ) ) +game ( + name "20 Second Platformer, A (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "20 Second Platformer, A (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "20 Second Platformer, A (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 2edc4684 sha1 a00b40a3f31bd875f4a0376d22099c3822c9ef98 ) +) + +game ( + name "20 Second Platformer, A (World) (GB Compatible) (Aftermarket) (Unl)" + description "20 Second Platformer, A (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "20 Second Platformer, A (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc ff0a848b sha1 837cbb4cf3a92266833099fa06b95edfcdb1865f ) +) + +game ( + name "2001 Fatal Fury (Taiwan) (En) (Unl)" + description "2001 Fatal Fury (Taiwan) (En) (Unl)" + rom ( name "2001 Fatal Fury (Taiwan) (En) (Unl).gbc" size 1048576 crc 7eda0e26 sha1 cd632530d71c560111bfc13a341f0f9a234db50a ) +) + +game ( + name "2002 Adventure Digimon 7 (Taiwan) (En) (Unl)" + description "2002 Adventure Digimon 7 (Taiwan) (En) (Unl)" + rom ( name "2002 Adventure Digimon 7 (Taiwan) (En) (Unl).gbc" size 2097152 crc 1bfc7099 sha1 532206800253fce0e81a0825ba49d60a7d6c5ca4 ) +) + +game ( + name "2002 Digimon Adventure 6 (Taiwan) (En) (Unl)" + description "2002 Digimon Adventure 6 (Taiwan) (En) (Unl)" + rom ( name "2002 Digimon Adventure 6 (Taiwan) (En) (Unl).gbc" size 1048576 crc 3f0d046b sha1 eea8928b277beb56ca8878b6dbfc094b0c3c5463 ) +) + +game ( + name "2003 Crash II Advance (USA) (Unl)" + description "2003 Crash II Advance (USA) (Unl)" + rom ( name "2003 Crash II Advance (USA) (Unl).gbc" size 2097152 crc 973d38a8 sha1 acdc42716f61bf11ecf08d50a980047f8fb7dc57 ) +) + +game ( + name "2003 Digimom Sapphii (Taiwan) (En) (Unl)" + description "2003 Digimom Sapphii (Taiwan) (En) (Unl)" + rom ( name "2003 Digimom Sapphii (Taiwan) (En) (Unl).gbc" size 2097152 crc 7cff9f0b sha1 1e42c461e0c6705637a698dbda8b34bc37acc51d ) +) + +game ( + name "2003 Digimom Sapphii (Taiwan) (De) (Unl)" + description "2003 Digimom Sapphii (Taiwan) (De) (Unl)" + rom ( name "2003 Digimom Sapphii (Taiwan) (De) (Unl).gbc" size 2097152 crc bd285d64 sha1 1cdffe470fde714898a2b0de92edd88e791a1bdf ) +) + +game ( + name "2003 Gu Huo Lang II (Taiwan) (Unl)" + description "2003 Gu Huo Lang II (Taiwan) (Unl)" + rom ( name "2003 Gu Huo Lang II (Taiwan) (Unl).gbc" size 2097152 crc 74d71b0c sha1 fcbb769de0896ae69fe1063fa5d87cf079c8606a ) +) + +game ( + name "2003 Hali Bote 2 - Xiaoshi de Mishi (Taiwan) (Unl)" + description "2003 Hali Bote 2 - Xiaoshi de Mishi (Taiwan) (Unl)" + rom ( name "2003 Hali Bote 2 - Xiaoshi de Mishi (Taiwan) (Unl).gbc" size 2097152 crc 1b3e1243 sha1 0829cbcab3ef5d03c94d5efe769f4f4a93ac47fa ) +) + +game ( + name "2003 Hali Xiaozi IV (Taiwan) (Unl)" + description "2003 Hali Xiaozi IV (Taiwan) (Unl)" + rom ( name "2003 Hali Xiaozi IV (Taiwan) (Unl).gbc" size 2097152 crc db3c8b95 sha1 0d230b20388f4396d6345b8eb59f54fc169ad8ee ) +) + +game ( + name "2003 Harry Potter 3 (Taiwan) (Unl)" + description "2003 Harry Potter 3 (Taiwan) (Unl)" + rom ( name "2003 Harry Potter 3 (Taiwan) (Unl).gbc" size 1048576 crc 4ea2c869 sha1 739c0e5dc0efd4ddb912236a6f630c3d6987d064 ) +) + +game ( + name "2003 King Lion Advance III (USA) (Unl)" + description "2003 King Lion Advance III (USA) (Unl)" + rom ( name "2003 King Lion Advance III (USA) (Unl).gbc" size 2097152 crc 0c22466d sha1 7c43ccfca93cae23e04e58fa0d7d7400a9694e0e ) +) + +game ( + name "2003 Koudai Guaishou - Lanbaoshi (Taiwan) (Unl)" + description "2003 Koudai Guaishou - Lanbaoshi (Taiwan) (Unl)" + rom ( name "2003 Koudai Guaishou - Lanbaoshi (Taiwan) (Unl).gbc" size 2097152 crc 4c76d4d8 sha1 d688201e6031b88f122ec753a37daedfb233b48d ) +) + +game ( + name "2003 Pocket Monster - Carbuncle (USA) (Unl)" + description "2003 Pocket Monster - Carbuncle (USA) (Unl)" + rom ( name "2003 Pocket Monster - Carbuncle (USA) (Unl).gbc" size 2097152 crc 3a0e9b6f sha1 025973627743f2f1ae1ff5b8a3f549cbcc227ef3 ) +) + +game ( + name "2003 Shuma Baolong - Gedou Ban (Taiwan) (Unl)" + description "2003 Shuma Baolong - Gedou Ban (Taiwan) (Unl)" + rom ( name "2003 Shuma Baolong - Gedou Ban (Taiwan) (Unl).gbc" size 2097152 crc 1219eec6 sha1 4a722c10e3893e04c67a66d0aea401d6d220ec7e ) +) + +game ( + name "2123 (World) (Aftermarket) (Unl)" + description "2123 (World) (Aftermarket) (Unl)" + rom ( name "2123 (World) (Aftermarket) (Unl).gbc" size 262144 crc 22836942 sha1 eb9a2aff6485962f1a7773b7138f3c4208fa36e4 ) +) + game ( name "23 in 1 (Taiwan) (Unl)" description "23 in 1 (Taiwan) (Unl)" @@ -33048,6 +34610,12 @@ game ( rom ( name "3D Pool Allstars (USA) (En,Fr,Es) (Proto).gbc" size 1048576 crc 245de3e2 sha1 f7289c3eed275286d0fb3dc7097098276b746786 ) ) +game ( + name "3D Quasars (World) (Aftermarket) (Unl)" + description "3D Quasars (World) (Aftermarket) (Unl)" + rom ( name "3D Quasars (World) (Aftermarket) (Unl).gbc" size 262144 crc 1fd94e67 sha1 3f32226538d8c7f0c866c4b73e9f828265f2bb5b ) +) + game ( name "4 in 1 + 8 in 1 (World) (4B-001, 4B-009, 8B-001, Sachen) (Unl)" description "4 in 1 + 8 in 1 (World) (4B-001, 4B-009, 8B-001, Sachen) (Unl)" @@ -33085,9 +34653,9 @@ game ( ) game ( - name "Aardvark (World) (Aftermarket) (Homebrew)" - description "Aardvark (World) (Aftermarket) (Homebrew)" - rom ( name "Aardvark (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 270d45b9 sha1 34a8d00af6be9083409e6fccd0825c6f185d135d flags verified ) + name "Aardvark (World) (Aftermarket) (Unl)" + description "Aardvark (World) (Aftermarket) (Unl)" + rom ( name "Aardvark (World) (Aftermarket) (Unl).gbc" size 262144 crc 270d45b9 sha1 34a8d00af6be9083409e6fccd0825c6f185d135d flags verified ) ) game ( @@ -33099,7 +34667,7 @@ game ( game ( name "Action Man - Search for Base X (USA, Europe)" description "Action Man - Search for Base X (USA, Europe)" - rom ( name "Action Man - Search for Base X (USA, Europe).gbc" size 1048576 crc 1226499e sha1 4b62b0344b8fed07ceb967f9a9c45bbeed3dc592 ) + rom ( name "Action Man - Search for Base X (USA, Europe).gbc" size 1048576 crc 1226499e sha1 4b62b0344b8fed07ceb967f9a9c45bbeed3dc592 flags verified ) ) game ( @@ -33115,9 +34683,21 @@ game ( ) game ( - name "Adventure Digimon 7 2002 (Taiwan) (En) (Unl)" - description "Adventure Digimon 7 2002 (Taiwan) (En) (Unl)" - rom ( name "Adventure Digimon 7 2002 (Taiwan) (En) (Unl).gbc" size 2097152 crc 1bfc7099 sha1 532206800253fce0e81a0825ba49d60a7d6c5ca4 ) + name "Adulting! Soundtrack (World) (GB Compatible) (Aftermarket) (Unl)" + description "Adulting! Soundtrack (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Adulting! Soundtrack (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 1b5b9e64 sha1 c5dad32be800c36814a0f9b940e99b5eada34150 ) +) + +game ( + name "Adventures in Carnal Hell, The (World) (v1.02) (GB Compatible) (Aftermarket) (Unl)" + description "Adventures in Carnal Hell, The (World) (v1.02) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Adventures in Carnal Hell, The (World) (v1.02) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 9f81e7a0 sha1 895148bc0a3b6f9ec59bebae43413d1f4eafd21a ) +) + +game ( + name "Adventures in Carnal Hell, The (World) (v1.01) (GB Compatible) (Aftermarket) (Unl)" + description "Adventures in Carnal Hell, The (World) (v1.01) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Adventures in Carnal Hell, The (World) (v1.01) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc a5d0d1ec sha1 bc6367f77c235640cea5a1230cee253c99f846e5 ) ) game ( @@ -33127,15 +34707,27 @@ game ( ) game ( - name "Agent B (World) (Aftermarket) (Homebrew)" - description "Agent B (World) (Aftermarket) (Homebrew)" - rom ( name "Agent B (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 31b6e3fa sha1 11b3ce59c4eb86cee05873eb473dbf262cf986bd ) + name "AF+ER (World) (GB Compatible) (Aftermarket) (Unl)" + description "AF+ER (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "AF+ER (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc f689b91e sha1 e55e427819916bb02189efe3883fb1dab3d80d35 ) ) game ( - name "Agent B (World) (Demo) (Aftermarket) (Homebrew)" - description "Agent B (World) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Agent B (World) (Demo) (Aftermarket) (Homebrew).gbc" size 262144 crc ae767ad7 sha1 1a332aac66b24381f16819d1145fd4a917f2e0f3 ) + name "Agency (World) (Aftermarket) (Unl)" + description "Agency (World) (Aftermarket) (Unl)" + rom ( name "Agency (World) (Aftermarket) (Unl).gbc" size 1048576 crc 0d1bb2f7 sha1 5266589244fab2e9ff047af9f72641cda91e1d90 ) +) + +game ( + name "Agent B (World) (GB Compatible) (Aftermarket) (Unl)" + description "Agent B (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Agent B (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 31b6e3fa sha1 11b3ce59c4eb86cee05873eb473dbf262cf986bd ) +) + +game ( + name "Agent B (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Agent B (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Agent B (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc ae767ad7 sha1 1a332aac66b24381f16819d1145fd4a917f2e0f3 ) ) game ( @@ -33186,6 +34778,12 @@ game ( rom ( name "Aliens - Thanatos Encounter (USA, Europe).gbc" size 1048576 crc bec3c24b sha1 e1b1c79c15a34984dddbe270fc6770b32a31a0d7 ) ) +game ( + name "All Humans Must Die! (World) (GB Compatible) (Aftermarket) (Unl)" + description "All Humans Must Die! (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "All Humans Must Die! (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc b4d50eed sha1 f4513fc525cbcfa4a2804b55ce20c809e01d1c87 ) +) + game ( name "All Star Tennis 2000 (Europe) (AZTP) (GB Compatible)" description "All Star Tennis 2000 (Europe) (AZTP) (GB Compatible)" @@ -33216,6 +34814,24 @@ game ( rom ( name "All-Star Baseball 2001 (USA).gbc" size 1048576 crc bc562466 sha1 f702df64d368b763187a5b1263a60fb3e842962b ) ) +game ( + name "Alley Cat (World) (Aftermarket) (Unl)" + description "Alley Cat (World) (Aftermarket) (Unl)" + rom ( name "Alley Cat (World) (Aftermarket) (Unl).gbc" size 262144 crc edb3ac37 sha1 a9aa1ecad6b67a6e5096fb1c10e39899c00a96a0 ) +) + +game ( + name "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + description "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl) (Beta)" + rom ( name "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl) (Beta).gbc" size 4194304 crc 7c101475 sha1 120e2dd012cfe47a7e37cc91fcbbce92494bdf2a ) +) + +game ( + name "Alone in the Dark - The New Nightmare (USA) (Beta) (2001-02-21)" + description "Alone in the Dark - The New Nightmare (USA) (Beta) (2001-02-21)" + rom ( name "Alone in the Dark - The New Nightmare (USA) (Beta) (2001-02-21).gbc" size 4194304 crc 3821d140 sha1 fc2a7dbe5ff60e2704ac78f83d6b6df2bf9dcc97 ) +) + game ( name "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl)" description "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl)" @@ -33228,12 +34844,6 @@ game ( rom ( name "Alone in the Dark - The New Nightmare (USA) (En,Fr,Es).gbc" size 4194304 crc c145c036 sha1 a348aeac500d0d8fdaf90f5277631a026504ff44 ) ) -game ( - name "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl) (Beta)" - description "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl) (Beta)" - rom ( name "Alone in the Dark - The New Nightmare (Europe) (En,Fr,De,Es,It,Nl) (Beta).gbc" size 4194304 crc 7c101475 sha1 120e2dd012cfe47a7e37cc91fcbbce92494bdf2a ) -) - game ( name "AMF Bowling (USA) (Proto)" description "AMF Bowling (USA) (Proto)" @@ -33270,6 +34880,12 @@ game ( rom ( name "Animorphs (USA).gbc" size 1048576 crc b4f293cc sha1 b3e5b34d5e97c49720861fabb6a29d557029279c ) ) +game ( + name "Another Adventure (World) (En,Es) (GB Compatible) (Aftermarket) (Unl)" + description "Another Adventure (World) (En,Es) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Another Adventure (World) (En,Es) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc dfcd02ef sha1 041473b2381dd9e11b3cbda5858f9841324327af ) +) + game ( name "Anpfiff - Der RTL Fussball-Manager (Germany)" description "Anpfiff - Der RTL Fussball-Manager (Germany)" @@ -33312,12 +34928,24 @@ game ( rom ( name "Antz World Sportz (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 67c7f85c sha1 d8ddf04baad3beadedf85847964f986ba89bc5ee ) ) +game ( + name "Apollo Mission (World) (Aftermarket) (Unl)" + description "Apollo Mission (World) (Aftermarket) (Unl)" + rom ( name "Apollo Mission (World) (Aftermarket) (Unl).gbc" size 262144 crc bec9d9a2 sha1 b2bcc61bcf269c0f5c0ce2a6e0bb1c7015dc9ff9 ) +) + game ( name "Aqualife (Japan) (SGB Enhanced) (GB Compatible)" description "Aqualife (Japan) (SGB Enhanced) (GB Compatible)" rom ( name "Aqualife (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc e243feb4 sha1 69eaf53eccdaf98cd7cc0d436209f511b558d761 ) ) +game ( + name "Arena 3000 (World) (Aftermarket) (Unl)" + description "Arena 3000 (World) (Aftermarket) (Unl)" + rom ( name "Arena 3000 (World) (Aftermarket) (Unl).gbc" size 262144 crc 9c17c15c sha1 007d23f73f68de01c250ec3d07403679137851ff ) +) + game ( name "Arle no Bouken - Mahou no Jewel (Japan) (SGB Enhanced) (GB Compatible)" description "Arle no Bouken - Mahou no Jewel (Japan) (SGB Enhanced) (GB Compatible)" @@ -33345,7 +34973,7 @@ game ( game ( name "Army Men - Air Combat (USA, Europe) (En,Fr,De)" description "Army Men - Air Combat (USA, Europe) (En,Fr,De)" - rom ( name "Army Men - Air Combat (USA, Europe) (En,Fr,De).gbc" size 1048576 crc b0d1de8c sha1 4e1d964d31013e79ecae4a49dcd3777cc7e06af2 ) + rom ( name "Army Men - Air Combat (USA, Europe) (En,Fr,De).gbc" size 1048576 crc b0d1de8c sha1 4e1d964d31013e79ecae4a49dcd3777cc7e06af2 flags verified ) ) game ( @@ -33357,7 +34985,7 @@ game ( game ( name "Army Men 2 (USA, Europe) (En,Fr,De)" description "Army Men 2 (USA, Europe) (En,Fr,De)" - rom ( name "Army Men 2 (USA, Europe) (En,Fr,De).gbc" size 1048576 crc 2272baca sha1 6e52dcaca1a97ae557c4c87e4281667a9d9b14c5 ) + rom ( name "Army Men 2 (USA, Europe) (En,Fr,De).gbc" size 1048576 crc 2272baca sha1 6e52dcaca1a97ae557c4c87e4281667a9d9b14c5 flags verified ) ) game ( @@ -33369,7 +34997,7 @@ game ( game ( name "Asterix - Sur la Trace D'Idefix (Europe) (En,Fr,De,Es,It,Nl)" description "Asterix - Sur la Trace D'Idefix (Europe) (En,Fr,De,Es,It,Nl)" - rom ( name "Asterix - Sur la Trace D'Idefix (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 408dc5c6 sha1 5c7207137ab422d3326d183d3433db161d8ecbc5 ) + rom ( name "Asterix - Sur la Trace D'Idefix (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc 408dc5c6 sha1 5c7207137ab422d3326d183d3433db161d8ecbc5 flags verified ) ) game ( @@ -33390,6 +35018,18 @@ game ( rom ( name "Asteroids (USA, Europe) (GB Compatible).gbc" size 1048576 crc 89d5d936 sha1 026f031e1bb787a4390e7873227dcb52a069a6e0 flags verified ) ) +game ( + name "Astro Plumber (World) (Aftermarket) (Unl)" + description "Astro Plumber (World) (Aftermarket) (Unl)" + rom ( name "Astro Plumber (World) (Aftermarket) (Unl).gbc" size 262144 crc d746db41 sha1 bf46ab2a3a1ffc3b712b9ae5cfa05441781ac9e4 ) +) + +game ( + name "Astro-Jump - The Sequel (World) (GB Compatible) (Aftermarket) (Unl)" + description "Astro-Jump - The Sequel (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Astro-Jump - The Sequel (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc e6a96130 sha1 2cd0ef086c4b89497d9497a17d871a6568a9e2d3 ) +) + game ( name "Atlantis - The Lost Empire (Europe) (En,Es,It)" description "Atlantis - The Lost Empire (Europe) (En,Es,It)" @@ -33408,6 +35048,12 @@ game ( rom ( name "Atlantis - The Lost Empire (USA, Europe).gbc" size 2097152 crc d594d24b sha1 ab5dd8efa36b33ce9aa090b3d990e8fc8828f7e2 ) ) +game ( + name "Atop the Witch's Tower (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Atop the Witch's Tower (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Atop the Witch's Tower (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 0d60b100 sha1 9cc1a5140b96ad072d36151f5d99ff6eb699e605 ) +) + game ( name "Atsumete Asobu Kuma no Pooh-san - Mori no Takaramono (Japan)" description "Atsumete Asobu Kuma no Pooh-san - Mori no Takaramono (Japan)" @@ -33469,9 +35115,15 @@ game ( ) game ( - name "Auto Zone (World) (Aftermarket) (Homebrew)" - description "Auto Zone (World) (Aftermarket) (Homebrew)" - rom ( name "Auto Zone (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 2a86d386 sha1 83a37fb5c5d82e0ff06bb22b63761af996e4ad61 ) + name "Auto Zone (World) (Aftermarket) (Unl)" + description "Auto Zone (World) (Aftermarket) (Unl)" + rom ( name "Auto Zone (World) (Aftermarket) (Unl).gbc" size 524288 crc 2a86d386 sha1 83a37fb5c5d82e0ff06bb22b63761af996e4ad61 ) +) + +game ( + name "Autumn With You, An (World) (GB Compatible) (Aftermarket) (Unl)" + description "Autumn With You, An (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Autumn With You, An (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc eac459fa sha1 68a5520be76c52a4936ad1756ea274667f2ac0e3 ) ) game ( @@ -33513,7 +35165,7 @@ game ( game ( name "Babe and Friends (Europe) (En,Fr,De,Es,It) (GB Compatible)" description "Babe and Friends (Europe) (En,Fr,De,Es,It) (GB Compatible)" - rom ( name "Babe and Friends (Europe) (En,Fr,De,Es,It) (GB Compatible).gbc" size 1048576 crc b3681854 sha1 52a560185b7e77e5286771f7851f69323512658e ) + rom ( name "Babe and Friends (Europe) (En,Fr,De,Es,It) (GB Compatible).gbc" size 1048576 crc b3681854 sha1 52a560185b7e77e5286771f7851f69323512658e flags verified ) ) game ( @@ -33535,9 +35187,9 @@ game ( ) game ( - name "Back to Nature (World) (Aftermarket) (Homebrew)" - description "Back to Nature (World) (Aftermarket) (Homebrew)" - rom ( name "Back to Nature (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 861f9a63 sha1 3f4a6cd105d4c8af0312bef482c08784bbbfb0eb ) + name "Back to Nature (World) (Aftermarket) (Unl)" + description "Back to Nature (World) (Aftermarket) (Unl)" + rom ( name "Back to Nature (World) (Aftermarket) (Unl).gbc" size 262144 crc 861f9a63 sha1 3f4a6cd105d4c8af0312bef482c08784bbbfb0eb ) ) game ( @@ -33607,9 +35259,9 @@ game ( ) game ( - name "Bandits at Zero (World) (Aftermarket) (Homebrew)" - description "Bandits at Zero (World) (Aftermarket) (Homebrew)" - rom ( name "Bandits at Zero (World) (Aftermarket) (Homebrew).gbc" size 524288 crc c70f413e sha1 c885e109fbb53445db9618c6768c2259e6135921 ) + name "Bandits at Zero (World) (Aftermarket) (Unl)" + description "Bandits at Zero (World) (Aftermarket) (Unl)" + rom ( name "Bandits at Zero (World) (Aftermarket) (Unl).gbc" size 524288 crc c70f413e sha1 c885e109fbb53445db9618c6768c2259e6135921 ) ) game ( @@ -33738,6 +35390,12 @@ game ( rom ( name "Battle Fishers (Japan).gbc" size 2097152 crc c99cf3c5 sha1 25d063b151c2d45a14d6952196490615b7e341c5 ) ) +game ( + name "Battle Star (World) (Aftermarket) (Unl)" + description "Battle Star (World) (Aftermarket) (Unl)" + rom ( name "Battle Star (World) (Aftermarket) (Unl).gbc" size 524288 crc b2fd062f sha1 ac4206129704e31386c9c0a1c961a148398f0ba3 ) +) + game ( name "Battleship (USA, Europe) (GB Compatible)" description "Battleship (USA, Europe) (GB Compatible)" @@ -33777,7 +35435,7 @@ game ( game ( name "Beatmania GB (Japan) (SGB Enhanced) (GB Compatible)" description "Beatmania GB (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Beatmania GB (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 0d9cb195 sha1 640c4633fe8ec60b767c15a094c87ab7e113d555 ) + rom ( name "Beatmania GB (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 0d9cb195 sha1 640c4633fe8ec60b767c15a094c87ab7e113d555 flags verified ) ) game ( @@ -33811,9 +35469,9 @@ game ( ) game ( - name "Berks (World) (Aftermarket) (Homebrew)" - description "Berks (World) (Aftermarket) (Homebrew)" - rom ( name "Berks (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 10ded9ab sha1 8b4c282cf973cdd9926a69ae1d8fcbaf79f8552b ) + name "Berks (World) (Aftermarket) (Unl)" + description "Berks (World) (Aftermarket) (Unl)" + rom ( name "Berks (World) (Aftermarket) (Unl).gbc" size 262144 crc 10ded9ab sha1 8b4c282cf973cdd9926a69ae1d8fcbaf79f8552b ) ) game ( @@ -33834,6 +35492,12 @@ game ( rom ( name "Bibi und Tina - Fohlen Felix in Gefahr (Germany).gbc" size 1048576 crc 8874acd4 sha1 59843ced1e9cbcb02c6acbb8f533ec77b314882c flags verified ) ) +game ( + name "BIG2SMALL (World) (Digital) (GB Compatible) (Aftermarket) (Unl)" + description "BIG2SMALL (World) (Digital) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "BIG2SMALL (World) (Digital) (GB Compatible) (Aftermarket) (Unl).gbc" size 65536 crc b0401d96 sha1 ee5f2db597bb2fa06efe4a279a887b97bf23cac6 ) +) + game ( name "Bikkuriman 2000 - Charging Card GB (Japan) (SGB Enhanced) (GB Compatible)" description "Bikkuriman 2000 - Charging Card GB (Japan) (SGB Enhanced) (GB Compatible)" @@ -33853,21 +35517,27 @@ game ( ) game ( - name "Bing Yuan Li Xian Ji (Taiwan) (Unl)" - description "Bing Yuan Li Xian Ji (Taiwan) (Unl)" - rom ( name "Bing Yuan Li Xian Ji (Taiwan) (Unl).gbc" size 2097152 crc 7ca57891 sha1 1bebc84f0fbfa731f33343c56032c8fe5803e4ae ) + name "Binary Monster 2 (Taiwan) (En) (Unl)" + description "Binary Monster 2 (Taiwan) (En) (Unl)" + rom ( name "Binary Monster 2 (Taiwan) (En) (Unl).gbc" size 131072 crc 16297b29 sha1 bccc7bd374166171f4961b8773bb881050b8a62d ) ) game ( - name "Bing Yuan Li Xian Ji II (Taiwan) (Unl) (Alt)" - description "Bing Yuan Li Xian Ji II (Taiwan) (Unl) (Alt)" - rom ( name "Bing Yuan Li Xian Ji II (Taiwan) (Unl) (Alt).gbc" size 2097152 crc b149f421 sha1 39060bd6fa872738ae126b64f123a1242d06680a ) + name "Bingyuan Lixian Ji (Taiwan) (Unl)" + description "Bingyuan Lixian Ji (Taiwan) (Unl)" + rom ( name "Bingyuan Lixian Ji (Taiwan) (Unl).gbc" size 2097152 crc 7ca57891 sha1 1bebc84f0fbfa731f33343c56032c8fe5803e4ae ) ) game ( - name "Bing Yuan Li Xian Ji II (Taiwan) (Unl)" - description "Bing Yuan Li Xian Ji II (Taiwan) (Unl)" - rom ( name "Bing Yuan Li Xian Ji II (Taiwan) (Unl).gbc" size 2097152 crc c4eba914 sha1 9e1c0c019630d7e4884ad3d5a447bd1acf668277 ) + name "Bingyuan Lixian Ji II (Taiwan) (Unl) (Alt)" + description "Bingyuan Lixian Ji II (Taiwan) (Unl) (Alt)" + rom ( name "Bingyuan Lixian Ji II (Taiwan) (Unl) (Alt).gbc" size 2097152 crc b149f421 sha1 39060bd6fa872738ae126b64f123a1242d06680a ) +) + +game ( + name "Bingyuan Lixian Ji II (Taiwan) (Unl)" + description "Bingyuan Lixian Ji II (Taiwan) (Unl)" + rom ( name "Bingyuan Lixian Ji II (Taiwan) (Unl).gbc" size 2097152 crc c4eba914 sha1 9e1c0c019630d7e4884ad3d5a447bd1acf668277 ) ) game ( @@ -33882,6 +35552,18 @@ game ( rom ( name "Bionic Commando - Elite Forces (USA, Australia).gbc" size 2097152 crc a663cf31 sha1 33c28a2183f8b95cc2d8e0b6a0b005bfc230f1fc flags verified ) ) +game ( + name "Bitterroot (World) (En) (GB Compatible) (Aftermarket) (Unl)" + description "Bitterroot (World) (En) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Bitterroot (World) (En) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 0d464785 sha1 790b9d231f6e66027e76264ef646c7a7cb9c878c ) +) + +game ( + name "Bitterroot (World) (Es) (GB Compatible) (Aftermarket) (Unl)" + description "Bitterroot (World) (Es) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Bitterroot (World) (Es) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 936443e2 sha1 b874c45d4866d5ef0c0d9837502ae42dd0ea3787 ) +) + game ( name "Black Bass - Lure Fishing (USA, Europe) (GB Compatible)" description "Black Bass - Lure Fishing (USA, Europe) (GB Compatible)" @@ -33894,6 +35576,12 @@ game ( rom ( name "Black Onyx, The (Japan).gbc" size 1048576 crc 582fe338 sha1 b0f009023a25e575b59e55dec07cda2826f48b65 ) ) +game ( + name "Black Tape (World) (GB Compatible) (Aftermarket) (Unl)" + description "Black Tape (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Black Tape (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 45c5f990 sha1 ec8c467e955d69b2084805f11a954e0d90855461 ) +) + game ( name "Blade (USA, Europe)" description "Blade (USA, Europe)" @@ -33907,9 +35595,15 @@ game ( ) game ( - name "Blinky's Revenge (World) (Aftermarket) (Homebrew)" - description "Blinky's Revenge (World) (Aftermarket) (Homebrew)" - rom ( name "Blinky's Revenge (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 2d2f9c2b sha1 1c39cc02396c74e7b0b282ead510e94c77ff7f1e ) + name "Blaze (World) (Aftermarket) (Unl)" + description "Blaze (World) (Aftermarket) (Unl)" + rom ( name "Blaze (World) (Aftermarket) (Unl).gbc" size 262144 crc 7d2519c7 sha1 f9b1422a91cc1f3a55526ef8ba81b7a8297fc55e ) +) + +game ( + name "Blinky's Revenge (World) (Aftermarket) (Unl)" + description "Blinky's Revenge (World) (Aftermarket) (Unl)" + rom ( name "Blinky's Revenge (World) (Aftermarket) (Unl).gbc" size 262144 crc 2d2f9c2b sha1 1c39cc02396c74e7b0b282ead510e94c77ff7f1e ) ) game ( @@ -33924,6 +35618,12 @@ game ( rom ( name "Blue's Clues - Blue's Alphabet Book (USA).gbc" size 1048576 crc 748d1345 sha1 f703b54746cb2ef08deba2518ce7b7a3836142aa ) ) +game ( + name "Board (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Board (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Board (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 440a2260 sha1 8472981264122ea588d991628c51020545779926 ) +) + game ( name "Boarder Zone (USA)" description "Boarder Zone (USA)" @@ -33960,6 +35660,12 @@ game ( rom ( name "Bob the Builder - Fix it Fun! (USA).gbc" size 1048576 crc 93fa37bd sha1 68bd9a1932d4e5333ab5b4dfe0d28f126e5d470f ) ) +game ( + name "Boing! (World) (Aftermarket) (Unl)" + description "Boing! (World) (Aftermarket) (Unl)" + rom ( name "Boing! (World) (Aftermarket) (Unl).gbc" size 2097152 crc 91961796 sha1 09fde4065941784bab4cf8f624a0398049ed4add ) +) + game ( name "Boku no Camp-jou (Japan)" description "Boku no Camp-jou (Japan)" @@ -33985,9 +35691,9 @@ game ( ) game ( - name "Bomberman 3 (Taiwan) (Unl)" - description "Bomberman 3 (Taiwan) (Unl)" - rom ( name "Bomberman 3 (Taiwan) (Unl).gbc" size 2097152 crc 8059e009 sha1 84011e3ae407613cfd7b6b1fe85f3812097afc66 ) + name "Bomb Runner 1-2 (World) (Aftermarket) (Unl)" + description "Bomb Runner 1-2 (World) (Aftermarket) (Unl)" + rom ( name "Bomb Runner 1-2 (World) (Aftermarket) (Unl).gbc" size 262144 crc d4c95ac0 sha1 3d020eb6e118b431899d79ce4a7bda9bc571c3a0 ) ) game ( @@ -34005,7 +35711,7 @@ game ( game ( name "Bomberman Max - Hikari no Yuusha (Japan)" description "Bomberman Max - Hikari no Yuusha (Japan)" - rom ( name "Bomberman Max - Hikari no Yuusha (Japan).gbc" size 2097152 crc 7a44ce88 sha1 9c38166e83e45707cbc2e0aff38fd4590dce7c3f ) + rom ( name "Bomberman Max - Hikari no Yuusha (Japan).gbc" size 2097152 crc 7a44ce88 sha1 9c38166e83e45707cbc2e0aff38fd4590dce7c3f flags verified ) ) game ( @@ -34017,7 +35723,7 @@ game ( game ( name "Bomberman Max - Yami no Senshi (Japan)" description "Bomberman Max - Yami no Senshi (Japan)" - rom ( name "Bomberman Max - Yami no Senshi (Japan).gbc" size 2097152 crc 48b60e8e sha1 12addfb8f890a44b87efb900e9d6ad5028b58936 ) + rom ( name "Bomberman Max - Yami no Senshi (Japan).gbc" size 2097152 crc 48b60e8e sha1 12addfb8f890a44b87efb900e9d6ad5028b58936 flags verified ) ) game ( @@ -34057,15 +35763,21 @@ game ( ) game ( - name "Booty (World) (Aftermarket) (Homebrew)" - description "Booty (World) (Aftermarket) (Homebrew)" - rom ( name "Booty (World) (Aftermarket) (Homebrew).gbc" size 262144 crc ef6c39c8 sha1 3c487ddc03d935b583e186d1cc395966ef490412 ) + name "Booty (World) (Aftermarket) (Unl)" + description "Booty (World) (Aftermarket) (Unl)" + rom ( name "Booty (World) (Aftermarket) (Unl).gbc" size 262144 crc ef6c39c8 sha1 3c487ddc03d935b583e186d1cc395966ef490412 ) ) game ( - name "Bouken! Dondoko-tou (Japan)" - description "Bouken! Dondoko-tou (Japan)" - rom ( name "Bouken! Dondoko-tou (Japan).gbc" size 2097152 crc 5fe759c7 sha1 c054abfea01a3ceb7b20b27e7ea937abe5157834 ) + name "Borbo's Quest (World) (GB Compatible) (Aftermarket) (Unl)" + description "Borbo's Quest (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Borbo's Quest (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc e92ce3d4 sha1 1ddf864188dfd741ccda0b0715e75e162d212605 ) +) + +game ( + name "Bouken! Dondoko Shima (Japan)" + description "Bouken! Dondoko Shima (Japan)" + rom ( name "Bouken! Dondoko Shima (Japan).gbc" size 2097152 crc 5fe759c7 sha1 c054abfea01a3ceb7b20b27e7ea937abe5157834 ) ) game ( @@ -34075,15 +35787,33 @@ game ( ) game ( - name "Brave Saga - Shinshou Astaria (Japan)" - description "Brave Saga - Shinshou Astaria (Japan)" - rom ( name "Brave Saga - Shinshou Astaria (Japan).gbc" size 2097152 crc 5d5d294a sha1 952b9e16a938b986a6216b8db6d62f71c4f853fa ) + name "Boxed In (World) (GB Compatible) (Aftermarket) (Unl)" + description "Boxed In (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Boxed In (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc ee1c2e1d sha1 b95dfdf10820671ab5f734ed7180cbf1967ca277 ) ) game ( - name "Bubble Trouble (World) (Aftermarket) (Homebrew)" - description "Bubble Trouble (World) (Aftermarket) (Homebrew)" - rom ( name "Bubble Trouble (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 3374918b sha1 892388f81f7815ea3bca17632a6a9a33a6edafac ) + name "Brave Saga - Shinshou Astaria (Japan)" + description "Brave Saga - Shinshou Astaria (Japan)" + rom ( name "Brave Saga - Shinshou Astaria (Japan).gbc" size 2097152 crc 5d5d294a sha1 952b9e16a938b986a6216b8db6d62f71c4f853fa flags verified ) +) + +game ( + name "Bub-O Escape - Tournament Edition (World) (Aftermarket) (Unl)" + description "Bub-O Escape - Tournament Edition (World) (Aftermarket) (Unl)" + rom ( name "Bub-O Escape - Tournament Edition (World) (Aftermarket) (Unl).gbc" size 524288 crc 437a2973 sha1 9c219e2c489f5140314e89fbdc0bb387e1f1eed0 ) +) + +game ( + name "Bubble Trouble (World) (Aftermarket) (Unl)" + description "Bubble Trouble (World) (Aftermarket) (Unl)" + rom ( name "Bubble Trouble (World) (Aftermarket) (Unl).gbc" size 262144 crc 3374918b sha1 892388f81f7815ea3bca17632a6a9a33a6edafac ) +) + +game ( + name "Bubblegum Attack (World) (GB Compatible) (Aftermarket) (Unl)" + description "Bubblegum Attack (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Bubblegum Attack (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc e3f64fec sha1 51e302fd27d579c9a4e8109e6ea4af3275d475dd ) ) game ( @@ -34146,12 +35876,6 @@ game ( rom ( name "Bugs Bunny in - Crazy Castle 4 (USA).gbc" size 1048576 crc 98dbffe0 sha1 a22b9765e901b2a23a48c44b0b829ab73b9c1a82 ) ) -game ( - name "Bulb! (World) (Aftermarket) (Homebrew)" - description "Bulb! (World) (Aftermarket) (Homebrew)" - rom ( name "Bulb! (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 650114a2 sha1 0c32d4b48a34614fb11fc69c17187d35ee22fabe ) -) - game ( name "Bundesliga Stars 2001 (Germany)" description "Bundesliga Stars 2001 (Germany)" @@ -34176,6 +35900,12 @@ game ( rom ( name "Burger Paradise International (Japan).gbc" size 1048576 crc 9092b0eb sha1 71072a7f0165769649bce8c31c36f67bb0e02963 ) ) +game ( + name "Buried Behind the Cabin (World) (GB Compatible) (Aftermarket) (Unl)" + description "Buried Behind the Cabin (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Buried Behind the Cabin (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc a5d6cd6a sha1 7464af8e6d9d0a4b11f510d22789a6830cd4c272 ) +) + game ( name "Bust-A-Move 4 (USA, Europe) (GB Compatible)" description "Bust-A-Move 4 (USA, Europe) (GB Compatible)" @@ -34212,6 +35942,18 @@ game ( rom ( name "Caise Gedou 29 in 1 Diannao Huamian Xuan Game (Taiwan) (Unl).gbc" size 2097152 crc 78c0e5bc sha1 358e628e680bc63227940ca6d76217d14fcd3409 flags verified ) ) +game ( + name "Cancer Culture VS The Illuminati (World) (2023-05-03) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Cancer Culture VS The Illuminati (World) (2023-05-03) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Cancer Culture VS The Illuminati (World) (2023-05-03) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 52da152b sha1 1bb4a376c03af67ca1e8426375fe1a644499d9ae ) +) + +game ( + name "Candy Quest (World) (v2) (Demo) (Aftermarket) (Unl)" + description "Candy Quest (World) (v2) (Demo) (Aftermarket) (Unl)" + rom ( name "Candy Quest (World) (v2) (Demo) (Aftermarket) (Unl).gbc" size 1048576 crc 1f2823cb sha1 8906832db7816be01ed37728f6e5a23e981e7e38 ) +) + game ( name "Cannon Fodder (Europe) (En,Fr,De,Es,It) (Beta)" description "Cannon Fodder (Europe) (En,Fr,De,Es,It) (Beta)" @@ -34278,6 +36020,12 @@ game ( rom ( name "Cardcaptor Sakura - Tomoeda Shougakkou Daiundoukai (Japan).gbc" size 2097152 crc f78f7998 sha1 1809154979b289750b572a61da1dc93b1b76360f ) ) +game ( + name "Cargo (World) (GB Compatible) (Aftermarket) (Unl)" + description "Cargo (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Cargo (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc a65d66f4 sha1 83c35ad553bde5ce3a6af418d7f8ad1fbe73b0f6 ) +) + game ( name "Carl Lewis Athletics 2000 (Europe) (En,Fr,De,Es,It,Nl)" description "Carl Lewis Athletics 2000 (Europe) (En,Fr,De,Es,It,Nl)" @@ -34350,6 +36098,12 @@ game ( rom ( name "Casper (USA).gbc" size 1048576 crc c775d653 sha1 82ac50380c3ed39fad13cc0bbe35e6457806a294 ) ) +game ( + name "Cat Boy's Stellar Journey (World) (GB Compatible) (Aftermarket) (Unl)" + description "Cat Boy's Stellar Journey (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Cat Boy's Stellar Journey (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 280937cc sha1 9ec53942f0136076b6468671562764e1ab9dee3b ) +) + game ( name "Caterpillar Construction Zone (USA, Europe) (GB Compatible)" description "Caterpillar Construction Zone (USA, Europe) (GB Compatible)" @@ -34386,6 +36140,18 @@ game ( rom ( name "Catz (USA).gbc" size 1048576 crc 769a2c5a sha1 5c3c9a4d85a92779c7e8304f2c122296f62f9a9c ) ) +game ( + name "Cave Fighter (World) (Aftermarket) (Unl)" + description "Cave Fighter (World) (Aftermarket) (Unl)" + rom ( name "Cave Fighter (World) (Aftermarket) (Unl).gbc" size 262144 crc 6f4641f0 sha1 05b441e3542452b1724017d20e2db602d0997773 ) +) + +game ( + name "Cave Hunter (World) (GB Compatible) (Aftermarket) (Unl)" + description "Cave Hunter (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Cave Hunter (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc defb3151 sha1 94770d13bd9b1b52224fe753f94ec580e1b4017c ) +) + game ( name "Centipede (Europe) (En,Fr,De,Es,It,Nl) (GB Compatible)" description "Centipede (Europe) (En,Fr,De,Es,It,Nl) (GB Compatible)" @@ -34399,9 +36165,9 @@ game ( ) game ( - name "CGB Test Cartridge (Japan) (En)" - description "CGB Test Cartridge (Japan) (En)" - rom ( name "CGB Test Cartridge (Japan) (En).gbc" size 65536 crc 4c050e29 sha1 5133d3dc7a4ced9d059dc72f0f351cb44e22f096 ) + name "CGB Test Cartridge (Japan) (En) [b]" + description "CGB Test Cartridge (Japan) (En) [b]" + rom ( name "CGB Test Cartridge (Japan) (En) [b].gbc" size 65536 crc 4c050e29 sha1 5133d3dc7a4ced9d059dc72f0f351cb44e22f096 flags baddump ) ) game ( @@ -34411,39 +36177,45 @@ game ( ) game ( - name "Chao Ji Ji Qi Ren Da Zhan X - Super Robot War X (Taiwan) (Unl)" - description "Chao Ji Ji Qi Ren Da Zhan X - Super Robot War X (Taiwan) (Unl)" - rom ( name "Chao Ji Ji Qi Ren Da Zhan X - Super Robot War X (Taiwan) (Unl).gbc" size 2097152 crc 279be0cc sha1 c2a64ba4c1fd60829429330bc13b70d9bd18f023 ) + name "Chao Jinhua - Shuma Baobei D-3 (Taiwan) (Unl)" + description "Chao Jinhua - Shuma Baobei D-3 (Taiwan) (Unl)" + rom ( name "Chao Jinhua - Shuma Baobei D-3 (Taiwan) (Unl).gbc" size 1048576 crc 1517d27e sha1 0d14f2e2ab630b6f99a8125e5c0120c2d7967270 ) ) game ( - name "Chao Ji Ji Qi Ren Da Zhan X - Super Robot War X (Taiwan) (Unl) (Alt)" - description "Chao Ji Ji Qi Ren Da Zhan X - Super Robot War X (Taiwan) (Unl) (Alt)" - rom ( name "Chao Ji Ji Qi Ren Da Zhan X - Super Robot War X (Taiwan) (Unl) (Alt).gbc" size 2097152 crc 1feaeb47 sha1 26d5841fc898dab17458dc39e871dab4947a7f2b ) -) - -game ( - name "Chao Jin Hua - Shu Ma Bao Bei D-3 (Taiwan) (Unl)" - description "Chao Jin Hua - Shu Ma Bao Bei D-3 (Taiwan) (Unl)" - rom ( name "Chao Jin Hua - Shu Ma Bao Bei D-3 (Taiwan) (Unl).gbc" size 1048576 crc 1517d27e sha1 0d14f2e2ab630b6f99a8125e5c0120c2d7967270 ) -) - -game ( - name "Chao Jinhua Shuma Baolong - Zuanshi Ban (Taiwan) (Unl)" - description "Chao Jinhua Shuma Baolong - Zuanshi Ban (Taiwan) (Unl)" - rom ( name "Chao Jinhua Shuma Baolong - Zuanshi Ban (Taiwan) (Unl).gbc" size 1048576 crc 50babe99 sha1 c153550886e812f5e37746fe1be6f294f13f97b3 ) + name "Chao Jinhua - Shuma Baolong - Zuanshi Ban (Taiwan) (Unl)" + description "Chao Jinhua - Shuma Baolong - Zuanshi Ban (Taiwan) (Unl)" + rom ( name "Chao Jinhua - Shuma Baolong - Zuanshi Ban (Taiwan) (Unl).gbc" size 1048576 crc 50babe99 sha1 c153550886e812f5e37746fe1be6f294f13f97b3 ) ) game ( name "Chaoji Gedou 2001 Alpha (Taiwan) (Unl)" description "Chaoji Gedou 2001 Alpha (Taiwan) (Unl)" - rom ( name "Chaoji Gedou 2001 Alpha (Taiwan) (Unl).gbc" size 2097152 crc afd7a0cc sha1 f44f629687ec91aade40ff52014587003f728ec9 ) + rom ( name "Chaoji Gedou 2001 Alpha (Taiwan) (Unl).gbc" size 2097152 crc afd7a0cc sha1 f44f629687ec91aade40ff52014587003f728ec9 flags verified ) ) game ( - name "Chaoji Yinsu Xiaozi II - Super Sonik II (Taiwan) (Unl)" - description "Chaoji Yinsu Xiaozi II - Super Sonik II (Taiwan) (Unl)" - rom ( name "Chaoji Yinsu Xiaozi II - Super Sonik II (Taiwan) (Unl).gbc" size 2097152 crc a9dd9da7 sha1 006df0ddb10c5970002134da4d75ccc466e95edd ) + name "Chaoji Jiqiren Dazhan X - Super Robot War X (Taiwan) (Unl)" + description "Chaoji Jiqiren Dazhan X - Super Robot War X (Taiwan) (Unl)" + rom ( name "Chaoji Jiqiren Dazhan X - Super Robot War X (Taiwan) (Unl).gbc" size 2097152 crc 279be0cc sha1 c2a64ba4c1fd60829429330bc13b70d9bd18f023 ) +) + +game ( + name "Chaoji Jiqiren Dazhan X - Super Robot War X (Taiwan) (Unl) (Alt)" + description "Chaoji Jiqiren Dazhan X - Super Robot War X (Taiwan) (Unl) (Alt)" + rom ( name "Chaoji Jiqiren Dazhan X - Super Robot War X (Taiwan) (Unl) (Alt).gbc" size 2097152 crc 1feaeb47 sha1 26d5841fc898dab17458dc39e871dab4947a7f2b ) +) + +game ( + name "Chaoji Yinsu de Xiaozi II - Super Sonik II (Taiwan) (Unl)" + description "Chaoji Yinsu de Xiaozi II - Super Sonik II (Taiwan) (Unl)" + rom ( name "Chaoji Yinsu de Xiaozi II - Super Sonik II (Taiwan) (Unl).gbc" size 2097152 crc a9dd9da7 sha1 006df0ddb10c5970002134da4d75ccc466e95edd ) +) + +game ( + name "Chaoren Tegong Dui (Taiwan) (Unl)" + description "Chaoren Tegong Dui (Taiwan) (Unl)" + rom ( name "Chaoren Tegong Dui (Taiwan) (Unl).gbc" size 2097152 crc e1d61242 sha1 31f54bdfa59d1e76777f044c1ef4686552f715f6 flags verified ) ) game ( @@ -34458,6 +36230,12 @@ game ( rom ( name "Chase H.Q. - Secret Police (USA) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 7c7fdefc sha1 030b45eb8929c1512826f288e4ba035e0083505c ) ) +game ( + name "Chase the Chuck Wagon (World) (Aftermarket) (Unl)" + description "Chase the Chuck Wagon (World) (Aftermarket) (Unl)" + rom ( name "Chase the Chuck Wagon (World) (Aftermarket) (Unl).gbc" size 262144 crc 3c3d653c sha1 27b462be532a37c15798eba0fd48154eff596753 ) +) + game ( name "Checkmate (Japan) (En,Ja) (GB Compatible)" description "Checkmate (Japan) (En,Ja) (GB Compatible)" @@ -34476,6 +36254,12 @@ game ( rom ( name "Chessmaster (USA, Europe) (GB Compatible).gbc" size 1048576 crc 1c13dbb0 sha1 84930fa75eccc34a8e9fb6a0387791d437d1a442 flags verified ) ) +game ( + name "Chester's Big Ol' Day (World) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Chester's Big Ol' Day (World) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Chester's Big Ol' Day (World) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 490a874a sha1 92567a6a58739a38e0d7b35d1327ccb999527fa0 ) +) + game ( name "Chi to Ase to Namida no Koukou Yakyuu (Japan)" description "Chi to Ase to Namida no Koukou Yakyuu (Japan)" @@ -34501,9 +36285,15 @@ game ( ) game ( - name "Chong Wu Xiao Jing Ling - Jie Jin Ta Zhi Wang (Taiwan) (Unl)" - description "Chong Wu Xiao Jing Ling - Jie Jin Ta Zhi Wang (Taiwan) (Unl)" - rom ( name "Chong Wu Xiao Jing Ling - Jie Jin Ta Zhi Wang (Taiwan) (Unl).gbc" size 1048576 crc 620e785d sha1 74da832c2eeb27a4260fe6f42514539473f48b11 ) + name "Chongwu Xiao Jingling - Jiejin Ta Zhi Wang (Taiwan) (Unl)" + description "Chongwu Xiao Jingling - Jiejin Ta Zhi Wang (Taiwan) (Unl)" + rom ( name "Chongwu Xiao Jingling - Jiejin Ta Zhi Wang (Taiwan) (Unl).gbc" size 1048576 crc 620e785d sha1 74da832c2eeb27a4260fe6f42514539473f48b11 ) +) + +game ( + name "Chopper War (World) (Aftermarket) (Unl)" + description "Chopper War (World) (Aftermarket) (Unl)" + rom ( name "Chopper War (World) (Aftermarket) (Unl).gbc" size 524288 crc eb0f4f3e sha1 26970bb0753e792aaeb328e0f88d650acd413a9d ) ) game ( @@ -34513,9 +36303,15 @@ game ( ) game ( - name "Chuan Shuo (Taiwan) (Unl)" - description "Chuan Shuo (Taiwan) (Unl)" - rom ( name "Chuan Shuo (Taiwan) (Unl).gbc" size 2097152 crc 0b20d3af sha1 f390b702d4b160149c1030bcccb5ed6f76c0b94a ) + name "Choro-Q (World) (Aftermarket) (Unl)" + description "Choro-Q (World) (Aftermarket) (Unl)" + rom ( name "Choro-Q (World) (Aftermarket) (Unl).gbc" size 262144 crc e40e99bd sha1 8534c4fe58aef32b8cfd4812fa1f2c1094e6b129 ) +) + +game ( + name "Chuanshuo (Taiwan) (Unl)" + description "Chuanshuo (Taiwan) (Unl)" + rom ( name "Chuanshuo (Taiwan) (Unl).gbc" size 2097152 crc 0b20d3af sha1 f390b702d4b160149c1030bcccb5ed6f76c0b94a ) ) game ( @@ -34531,9 +36327,15 @@ game ( ) game ( - name "Climb It (World) (Aftermarket) (Homebrew)" - description "Climb It (World) (Aftermarket) (Homebrew)" - rom ( name "Climb It (World) (Aftermarket) (Homebrew).gbc" size 262144 crc e7210290 sha1 19f3b825eada3eda3135350bd0ddca6a20a5281f ) + name "Climb It (World) (Aftermarket) (Unl)" + description "Climb It (World) (Aftermarket) (Unl)" + rom ( name "Climb It (World) (Aftermarket) (Unl).gbc" size 262144 crc e7210290 sha1 19f3b825eada3eda3135350bd0ddca6a20a5281f ) +) + +game ( + name "Clockmaker's Tale, A (World) (GB Compatible) (Aftermarket) (Unl)" + description "Clockmaker's Tale, A (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Clockmaker's Tale, A (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc c4b00adb sha1 07e4254c7f74b9d4caa6a1231558b2430dff163a flags verified ) ) game ( @@ -34561,9 +36363,9 @@ game ( ) game ( - name "Commando (World) (Aftermarket) (Homebrew)" - description "Commando (World) (Aftermarket) (Homebrew)" - rom ( name "Commando (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 5381b103 sha1 414bb6bdc1ed5647707d7d49f194c387d4098f00 ) + name "Commando (World) (Aftermarket) (Unl)" + description "Commando (World) (Aftermarket) (Unl)" + rom ( name "Commando (World) (Aftermarket) (Unl).gbc" size 262144 crc 5381b103 sha1 414bb6bdc1ed5647707d7d49f194c387d4098f00 ) ) game ( @@ -34572,6 +36374,12 @@ game ( rom ( name "Conker's Pocket Tales (USA, Europe) (En,Fr,De) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc a50be9a8 sha1 e9c3b1bb20ea74f363191ea9144009d1b13246bb flags verified ) ) +game ( + name "Cookie's Bakery (World) (v1.0.3) (GB Compatible) (Aftermarket) (Unl)" + description "Cookie's Bakery (World) (v1.0.3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Cookie's Bakery (World) (v1.0.3) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc c53ace00 sha1 02fdc52bc934b80aa41520d92cf0340753d8f668 ) +) + game ( name "Cool Bricks (Europe) (En,Fr,De,Es,It)" description "Cool Bricks (Europe) (En,Fr,De,Es,It)" @@ -34585,9 +36393,21 @@ game ( ) game ( - name "Crash II Advance 2003 (USA) (Unl)" - description "Crash II Advance 2003 (USA) (Unl)" - rom ( name "Crash II Advance 2003 (USA) (Unl).gbc" size 2097152 crc 973d38a8 sha1 acdc42716f61bf11ecf08d50a980047f8fb7dc57 ) + name "Coria and the Sunken City (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Coria and the Sunken City (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Coria and the Sunken City (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc fe1bdae6 sha1 00d86bbdbc228ff3ea0684984a261cadbed5fb0a ) +) + +game ( + name "Cosmo Knight ZiON (World) (En) (v0.24) (Demo) (Aftermarket) (Unl)" + description "Cosmo Knight ZiON (World) (En) (v0.24) (Demo) (Aftermarket) (Unl)" + rom ( name "Cosmo Knight ZiON (World) (En) (v0.24) (Demo) (Aftermarket) (Unl).gbc" size 2097152 crc 1780b904 sha1 fcbe2c2389e6c51a38eb17eb80ffb2e51955c7f2 ) +) + +game ( + name "Cosmo Knight ZiON (World) (En,Es) (v0.47) (Demo) (Aftermarket) (Unl)" + description "Cosmo Knight ZiON (World) (En,Es) (v0.47) (Demo) (Aftermarket) (Unl)" + rom ( name "Cosmo Knight ZiON (World) (En,Es) (v0.47) (Demo) (Aftermarket) (Unl).gbc" size 2097152 crc e983a31f sha1 1d811dd440572243f9e95527d970f3ffa91ddbdf ) ) game ( @@ -34609,9 +36429,9 @@ game ( ) game ( - name "Crazy Golf (World) (Aftermarket) (Homebrew)" - description "Crazy Golf (World) (Aftermarket) (Homebrew)" - rom ( name "Crazy Golf (World) (Aftermarket) (Homebrew).gbc" size 262144 crc f7fe3d01 sha1 b06f47a713b66efa9133be43653c7c4cb5ebc93c ) + name "Crazy Golf (World) (Aftermarket) (Unl)" + description "Crazy Golf (World) (Aftermarket) (Unl)" + rom ( name "Crazy Golf (World) (Aftermarket) (Unl).gbc" size 262144 crc f7fe3d01 sha1 b06f47a713b66efa9133be43653c7c4cb5ebc93c ) ) game ( @@ -34669,9 +36489,9 @@ game ( ) game ( - name "Cuthbert in the Cooler (World) (Aftermarket) (Homebrew)" - description "Cuthbert in the Cooler (World) (Aftermarket) (Homebrew)" - rom ( name "Cuthbert in the Cooler (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 30204c4e sha1 d6fb35f3bdd44429f88c10551692e1adf14356ab ) + name "Cuthbert in the Cooler (World) (Aftermarket) (Unl)" + description "Cuthbert in the Cooler (World) (Aftermarket) (Unl)" + rom ( name "Cuthbert in the Cooler (World) (Aftermarket) (Unl).gbc" size 262144 crc 30204c4e sha1 d6fb35f3bdd44429f88c10551692e1adf14356ab ) ) game ( @@ -34713,7 +36533,7 @@ game ( game ( name "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced) (GB Compatible)" description "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 2f368da6 sha1 0854b7ea4791a460c75ce9096583934b1af053e8 ) + rom ( name "Daikaijuu Monogatari - Poyon no Dungeon Room (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 2f368da6 sha1 0854b7ea4791a460c75ce9096583934b1af053e8 flags verified ) ) game ( @@ -34752,6 +36572,36 @@ game ( rom ( name "Daiku no Gen-san - Kachikachi no Tonkachi ga Kachi (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc e2071293 sha1 2d961353e7242babce49dda8d017a459f4ef7609 ) ) +game ( + name "Daisu-ki (World) (v1.2.1) (Aftermarket) (Unl)" + description "Daisu-ki (World) (v1.2.1) (Aftermarket) (Unl)" + rom ( name "Daisu-ki (World) (v1.2.1) (Aftermarket) (Unl).gbc" size 262144 crc 502385c4 sha1 3a310be21d5cc077da6eb8e3afa99ccff2eda84e ) +) + +game ( + name "Daisu-ki (World) (v1.1) (Aftermarket) (Unl)" + description "Daisu-ki (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Daisu-ki (World) (v1.1) (Aftermarket) (Unl).gbc" size 262144 crc a504b906 sha1 4634631f2c0b4a618aeefc114e5b8e4ba9c7ee04 ) +) + +game ( + name "Daisu-ki (World) (v1.1.1) (Aftermarket) (Unl)" + description "Daisu-ki (World) (v1.1.1) (Aftermarket) (Unl)" + rom ( name "Daisu-ki (World) (v1.1.1) (Aftermarket) (Unl).gbc" size 262144 crc a9714871 sha1 7d5b22d1c528603007e340f9d3562c1e53f10796 ) +) + +game ( + name "Daisu-ki (World) (v1.2) (Aftermarket) (Unl)" + description "Daisu-ki (World) (v1.2) (Aftermarket) (Unl)" + rom ( name "Daisu-ki (World) (v1.2) (Aftermarket) (Unl).gbc" size 262144 crc 26d3fe7a sha1 36c9649d4e99fdcaa4cf590963d0c49a3cf8084e ) +) + +game ( + name "Daisu-ki - Jam Edition (World) (GB Compatible) (Aftermarket) (Unl)" + description "Daisu-ki - Jam Edition (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Daisu-ki - Jam Edition (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc d34b719a sha1 446ca937d3e54ce33a49d1fff4692b3b906b539e ) +) + game ( name "Dance Dance Revolution GB (Japan)" description "Dance Dance Revolution GB (Japan)" @@ -34782,6 +36632,12 @@ game ( rom ( name "Dancing Furby (Japan) (GB Compatible).gbc" size 1048576 crc 3263f692 sha1 f3f7e37d64eef74d65456bae490e0a0b25897ac0 ) ) +game ( + name "Dark Winter Wander, A (World) (GB Compatible) (Aftermarket) (Unl)" + description "Dark Winter Wander, A (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dark Winter Wander, A (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc df19aa9f sha1 412f18ba08f2f2a2afbf3bfb5281e360d7aba31d ) +) + game ( name "Data-Navi Pro Yakyuu (Japan)" description "Data-Navi Pro Yakyuu (Japan)" @@ -34818,6 +36674,24 @@ game ( rom ( name "David O'Leary's Total Soccer 2000 (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc c25ee35a sha1 be0703ee2667ddc53cff9d6c7d22b30d272c0738 ) ) +game ( + name "Dawn Will Come (World) (GB Compatible) (Aftermarket) (Unl)" + description "Dawn Will Come (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dawn Will Come (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc bb64f51c sha1 1611ddfdb9af72f20ddeca4133d8eebd0f14e424 ) +) + +game ( + name "Days Without (World) (Multiple Endings) (Aftermarket) (Unl)" + description "Days Without (World) (Multiple Endings) (Aftermarket) (Unl)" + rom ( name "Days Without (World) (Multiple Endings) (Aftermarket) (Unl).gbc" size 262144 crc 57ca8f69 sha1 8992f14f02bd37e11cb05511c17fff3d253ccf25 ) +) + +game ( + name "Days Without (World) (Aftermarket) (Unl)" + description "Days Without (World) (Aftermarket) (Unl)" + rom ( name "Days Without (World) (Aftermarket) (Unl).gbc" size 262144 crc 437b4921 sha1 cb21c1bca18d750ecde91dc3adb6b599c2ad75fa ) +) + game ( name "Deadly Skies (Europe) (En,Fr,De)" description "Deadly Skies (Europe) (En,Fr,De)" @@ -34830,12 +36704,24 @@ game ( rom ( name "Dear Daniel no Sweet Adventure - Kitty-chan o Sagashite (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 0fd34427 sha1 8598594285f0342b3d93c447b475fadd4722c6cb ) ) +game ( + name "Death Race 16 (World) (Aftermarket) (Unl)" + description "Death Race 16 (World) (Aftermarket) (Unl)" + rom ( name "Death Race 16 (World) (Aftermarket) (Unl).gbc" size 262144 crc 7b9488ec sha1 56b8a2d7117b12ff5e709e6a258f9a0b3b0ebe24 ) +) + game ( name "Deer Hunter (USA)" description "Deer Hunter (USA)" rom ( name "Deer Hunter (USA).gbc" size 1048576 crc 40a715fb sha1 87a012e82f2361760ae337b30e9d41ef2245419a ) ) +game ( + name "Deisanebe (World) (GB Compatible) (Aftermarket) (Unl)" + description "Deisanebe (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Deisanebe (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 7cff943e sha1 065b5325d44cb0e40f7b7803d707b8c1ea9ea5b2 ) +) + game ( name "Deja Vu I & II (Japan)" description "Deja Vu I & II (Japan)" @@ -34903,9 +36789,9 @@ game ( ) game ( - name "Digimom Sapphii 2003 (Taiwan) (En) (Unl)" - description "Digimom Sapphii 2003 (Taiwan) (En) (Unl)" - rom ( name "Digimom Sapphii 2003 (Taiwan) (En) (Unl).gbc" size 2097152 crc 7cff9f0b sha1 1e42c461e0c6705637a698dbda8b34bc37acc51d ) + name "Dia de Sol Noite de Lua (World) (GB Compatible) (Aftermarket) (Unl)" + description "Dia de Sol Noite de Lua (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dia de Sol Noite de Lua (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc c6b965b9 sha1 ac43f43bdcfc0347f24a0a70de213a4b701d8155 ) ) game ( @@ -34939,9 +36825,9 @@ game ( ) game ( - name "Digimon Adventure 6 2002 (Taiwan) (En) (Unl)" - description "Digimon Adventure 6 2002 (Taiwan) (En) (Unl)" - rom ( name "Digimon Adventure 6 2002 (Taiwan) (En) (Unl).gbc" size 1048576 crc 3f0d046b sha1 eea8928b277beb56ca8878b6dbfc094b0c3c5463 ) + name "Digimon Amethyst (USA) (Unl)" + description "Digimon Amethyst (USA) (Unl)" + rom ( name "Digimon Amethyst (USA) (Unl).gbc" size 2097152 crc 726eed2a sha1 0b5f44cc2f583182a91ed8a815a3e7cec3bd1a58 ) ) game ( @@ -34962,6 +36848,12 @@ game ( rom ( name "Digimon Saphire (USA) (Unl).gbc" size 1048576 crc be4c1d83 sha1 f5706a80bae20027d7643ab151607adbe13e6b1d ) ) +game ( + name "Digital Monster 2001 (Taiwan) (En) (Unl)" + description "Digital Monster 2001 (Taiwan) (En) (Unl)" + rom ( name "Digital Monster 2001 (Taiwan) (En) (Unl).gbc" size 524288 crc d9eb3f2a sha1 cc7d4a2e5bf1fbee8e0a0e0960f4038fca3e458f ) +) + game ( name "Dino Breeder 3 - Gaia Fukkatsu (Japan) (SGB Enhanced) (GB Compatible)" description "Dino Breeder 3 - Gaia Fukkatsu (Japan) (SGB Enhanced) (GB Compatible)" @@ -34998,6 +36890,18 @@ game ( rom ( name "Dinosaur'us (Europe) (En,Fr,De,Es,It,Nl).gbc" size 1048576 crc f4609fe3 sha1 d0caf4b5172651aee2bbe38efdae084ce3d7a7ff ) ) +game ( + name "Disco Elysium - Game Boy Edition (World) (Music) (GB Compatible) (Aftermarket) (Unl)" + description "Disco Elysium - Game Boy Edition (World) (Music) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Disco Elysium - Game Boy Edition (World) (Music) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc ef349515 sha1 06fe25086432c82f1e4b4c44473dd5b487a8af05 ) +) + +game ( + name "Disco Elysium - Game Boy Edition (World) (No Music) (GB Compatible) (Aftermarket) (Unl)" + description "Disco Elysium - Game Boy Edition (World) (No Music) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Disco Elysium - Game Boy Edition (World) (No Music) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 7c0f52cc sha1 8bc16b70838f9245b7e37c6dbe57159b294fbf81 ) +) + game ( name "Diva Starz (Europe)" description "Diva Starz (Europe)" @@ -35022,6 +36926,12 @@ game ( rom ( name "Diva Starz - Mall Mania (USA).gbc" size 1048576 crc ebe0ecd6 sha1 1d0edb87404409f1e4c124503be4cc59165c01da ) ) +game ( + name "Diver 94 (World) (GB Compatible) (Aftermarket) (Unl)" + description "Diver 94 (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Diver 94 (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc f4ff5eb0 sha1 6b421505acc626a34bb9306a3d88e1964a4502f3 ) +) + game ( name "Dogz (Europe)" description "Dogz (Europe)" @@ -35052,6 +36962,24 @@ game ( rom ( name "Dokidoki Densetsu - Mahoujin Guruguru (Japan).gbc" size 4194304 crc 83e47a1a sha1 1b4627699b45af36a42e75c1a217b40fb5bec4ba ) ) +game ( + name "Don't Forget About Me (World) (GB Compatible) (Aftermarket) (Unl)" + description "Don't Forget About Me (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Don't Forget About Me (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 52cf7153 sha1 74e6246405dd52d4c5c2eabc417946550c637164 ) +) + +game ( + name "Don't Forget About Me (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Don't Forget About Me (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Don't Forget About Me (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 8ca9dbe0 sha1 cf6eaac37c4ae1b3cfc4ed8d2ce73a143635b525 ) +) + +game ( + name "Don't Forget About Me (World) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + description "Don't Forget About Me (World) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Don't Forget About Me (World) (v1.2) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 3d87efd8 sha1 83201c43e9fc89f4393678ade8c6107b4cfdb628 ) +) + game ( name "Donald Duck - Daisy o Sukue! (Japan)" description "Donald Duck - Daisy o Sukue! (Japan)" @@ -35073,7 +37001,7 @@ game ( game ( name "Donkey Kong 2001 (Japan)" description "Donkey Kong 2001 (Japan)" - rom ( name "Donkey Kong 2001 (Japan).gbc" size 4194304 crc cb065eba sha1 5be5500d9ff9c4416df77816ebd21cca7a0b19de ) + rom ( name "Donkey Kong 2001 (Japan).gbc" size 4194304 crc cb065eba sha1 5be5500d9ff9c4416df77816ebd21cca7a0b19de flags verified ) ) game ( @@ -35161,9 +37089,9 @@ game ( ) game ( - name "Dork's Dilemma (World) (Aftermarket) (Homebrew)" - description "Dork's Dilemma (World) (Aftermarket) (Homebrew)" - rom ( name "Dork's Dilemma (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 77b8b43b sha1 bd525f97cc316fed3f6271ed0929414df4c0389c ) + name "Dork's Dilemma (World) (Aftermarket) (Unl)" + description "Dork's Dilemma (World) (Aftermarket) (Unl)" + rom ( name "Dork's Dilemma (World) (Aftermarket) (Unl).gbc" size 524288 crc 77b8b43b sha1 bd525f97cc316fed3f6271ed0929414df4c0389c ) ) game ( @@ -35190,6 +37118,12 @@ game ( rom ( name "Doug's Big Game (Europe).gbc" size 1048576 crc b6ffbcca sha1 e9c207bb9b03b5762afd53c8f5295703cc1474b1 ) ) +game ( + name "Downer (World) (GB Compatible) (Aftermarket) (Unl)" + description "Downer (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Downer (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 7a1c9a9f sha1 70044dca1282f4445fe05305586ecc69f4e52304 ) +) + game ( name "Dr. Rin ni Kiitemite! - Koi no Rin Fuusui (Japan)" description "Dr. Rin ni Kiitemite! - Koi no Rin Fuusui (Japan)" @@ -35214,6 +37148,12 @@ game ( rom ( name "Dragon Ball - Final Bout (Taiwan) (Unl).gbc" size 1048576 crc d9849157 sha1 51ebe1a27e8295340f996d2841c5cc6e2bc9f548 ) ) +game ( + name "Dragon Ball Z - 2002 Fighting (Taiwan) (Zh) (Unl)" + description "Dragon Ball Z - 2002 Fighting (Taiwan) (Zh) (Unl)" + rom ( name "Dragon Ball Z - 2002 Fighting (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 8fa35740 sha1 008a559635c9d351d9f68b3a1ac0c687521821cf ) +) + game ( name "Dragon Ball Z - Densetsu no Chou Senshi-tachi (Japan) (Beta) (All Unlocked)" description "Dragon Ball Z - Densetsu no Chou Senshi-tachi (Japan) (Beta) (All Unlocked)" @@ -35323,15 +37263,21 @@ game ( ) game ( - name "Dragon Ball Z 3 2002 Fighting (Taiwan) (En) (Unl)" - description "Dragon Ball Z 3 2002 Fighting (Taiwan) (En) (Unl)" - rom ( name "Dragon Ball Z 3 2002 Fighting (Taiwan) (En) (Unl).gbc" size 2097152 crc dbe0f44e sha1 baea9e5ee1411988039d563ece97d8d7f765396a ) + name "Dragon Ball Z 3 - 2002 Fighting (Taiwan) (En) (Unl)" + description "Dragon Ball Z 3 - 2002 Fighting (Taiwan) (En) (Unl)" + rom ( name "Dragon Ball Z 3 - 2002 Fighting (Taiwan) (En) (Unl).gbc" size 2097152 crc dbe0f44e sha1 baea9e5ee1411988039d563ece97d8d7f765396a ) ) game ( - name "Dragon Ball Z Fighting 2002 (Taiwan) (Zh) (Unl)" - description "Dragon Ball Z Fighting 2002 (Taiwan) (Zh) (Unl)" - rom ( name "Dragon Ball Z Fighting 2002 (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 8fa35740 sha1 008a559635c9d351d9f68b3a1ac0c687521821cf ) + name "Dragon Ball Z Gedou 2005 (Taiwan) (Unl)" + description "Dragon Ball Z Gedou 2005 (Taiwan) (Unl)" + rom ( name "Dragon Ball Z Gedou 2005 (Taiwan) (Unl).gbc" size 2097152 crc d1c48145 sha1 8637ed614dc94e846c32adbc723e09a06b3da3ce ) +) + +game ( + name "Dragon Dance (USA) (SGB Enhanced) (GB Compatible)" + description "Dragon Dance (USA) (SGB Enhanced) (GB Compatible)" + rom ( name "Dragon Dance (USA) (SGB Enhanced) (GB Compatible).gbc" size 262144 crc 0602dbe1 sha1 a28bfabc4db62ad5aa6bfe29114b0878429586cc ) ) game ( @@ -35352,12 +37298,6 @@ game ( rom ( name "Dragon Dance (USA) (Beta 2) (SGB Enhanced) (GB Compatible).gbc" size 262144 crc 9a90adbe sha1 5fc97752a98a18b7e2db238d1ab88c6b09e34602 ) ) -game ( - name "Dragon Dance (USA) (SGB Enhanced) (GB Compatible)" - description "Dragon Dance (USA) (SGB Enhanced) (GB Compatible)" - rom ( name "Dragon Dance (USA) (SGB Enhanced) (GB Compatible).gbc" size 262144 crc 0602dbe1 sha1 a28bfabc4db62ad5aa6bfe29114b0878429586cc ) -) - game ( name "Dragon Quest I & II (Japan) (SGB Enhanced) (GB Compatible)" description "Dragon Quest I & II (Japan) (SGB Enhanced) (GB Compatible)" @@ -35389,9 +37329,9 @@ game ( ) game ( - name "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP)" - description "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP)" - rom ( name "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP).gbc" size 2097152 crc 66b83e3a sha1 378794e041f2eb286f2d5243a3cada2faf265bb5 ) + name "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev 1) (Possible Proto) (SGB Enhanced) (GB Compatible) (Alt)" + description "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev 1) (Possible Proto) (SGB Enhanced) (GB Compatible) (Alt)" + rom ( name "Dragon Quest Monsters - Terry no Wonderland (Japan) (Rev 1) (Possible Proto) (SGB Enhanced) (GB Compatible) (Alt).gbc" size 2097152 crc 66b83e3a sha1 378794e041f2eb286f2d5243a3cada2faf265bb5 ) ) game ( @@ -35466,6 +37406,24 @@ game ( rom ( name "Dragon's Lair (USA, Europe) (En,Ja,Fr,De,Es,Zh).gbc" size 4194304 crc bf076ca5 sha1 15fb0865314e43a83910d52cca7307502aab29fc ) ) +game ( + name "Dragonborne DX (World) (v1.0.2) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Dragonborne DX (World) (v1.0.2) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dragonborne DX (World) (v1.0.2) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 4194304 crc 9f30b891 sha1 9974d28975a2d8e1e41ce8f32351c6eef144919d ) +) + +game ( + name "Dragonyhm (World) (v1.0) (Demo) (SGB Enhanced) (GB Compatible) (Aftermarket) (Unl)" + description "Dragonyhm (World) (v1.0) (Demo) (SGB Enhanced) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dragonyhm (World) (v1.0) (Demo) (SGB Enhanced) (GB Compatible) (Aftermarket) (Unl).gbc" size 4194304 crc 96f9b7c0 sha1 2b74d076cabff92e5935d922e8f37202a723aaf0 flags verified ) +) + +game ( + name "Dragonyhm (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Dragonyhm (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dragonyhm (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 4194304 crc cad7369d sha1 0058096f8fcbb2774f908811aaa0b1ee54111493 ) +) + game ( name "Driver (Europe) (En,Fr,De,Es,It)" description "Driver (Europe) (En,Fr,De,Es,It)" @@ -35538,6 +37496,18 @@ game ( rom ( name "Dungeon Savior (Japan) (Rev 1) (Proto) (SGB Enhanced) (GB Compatible).gbc" size 4194304 crc 0180364b sha1 c5e93f04cc41404320aaf70eb10b55465edb1083 ) ) +game ( + name "Dusky Dungeon (World) (v0.1.0) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Dusky Dungeon (World) (v0.1.0) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dusky Dungeon (World) (v0.1.0) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 7c41cef6 sha1 e2df238887da0b6cf79513c7799ad707740eae30 ) +) + +game ( + name "Dusky Dungeon (World) (v0.2.0) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Dusky Dungeon (World) (v0.2.0) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Dusky Dungeon (World) (v0.2.0) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc abb154db sha1 f3b456d6318bee05150403efa5a933996e1d744a ) +) + game ( name "DX Jinsei Game (Japan)" description "DX Jinsei Game (Japan)" @@ -35557,9 +37527,9 @@ game ( ) game ( - name "E Mo Dao (Taiwan) (Unl)" - description "E Mo Dao (Taiwan) (Unl)" - rom ( name "E Mo Dao (Taiwan) (Unl).gbc" size 524288 crc 2b2acb79 sha1 929784599694efc6db16163f5bf91e49c2e459fc ) + name "E.T. - The Extra-Terrestrial - Digital Companion (USA)" + description "E.T. - The Extra-Terrestrial - Digital Companion (USA)" + rom ( name "E.T. - The Extra-Terrestrial - Digital Companion (USA).gbc" size 1048576 crc 84872999 sha1 7dd940c8044ccc0e18a511fa32c73551ce30463e ) ) game ( @@ -35568,12 +37538,6 @@ game ( rom ( name "E.T. - The Extra-Terrestrial - Digital Companion (Europe) (Proto).gbc" size 1048576 crc 513f38b7 sha1 14ad36a7939be12d1212c12a59de31d27e4df8f3 ) ) -game ( - name "E.T. - The Extra-Terrestrial - Digital Companion (USA)" - description "E.T. - The Extra-Terrestrial - Digital Companion (USA)" - rom ( name "E.T. - The Extra-Terrestrial - Digital Companion (USA).gbc" size 1048576 crc 84872999 sha1 7dd940c8044ccc0e18a511fa32c73551ce30463e ) -) - game ( name "E.T. - The Extra-Terrestrial - Escape from Planet Earth (Europe) (En,Fr,De,Es,It,Nl)" description "E.T. - The Extra-Terrestrial - Escape from Planet Earth (Europe) (En,Fr,De,Es,It,Nl)" @@ -35601,7 +37565,7 @@ game ( game ( name "Earthworm Jim - Menace 2 the Galaxy (USA, Europe) (GB Compatible)" description "Earthworm Jim - Menace 2 the Galaxy (USA, Europe) (GB Compatible)" - rom ( name "Earthworm Jim - Menace 2 the Galaxy (USA, Europe) (GB Compatible).gbc" size 1048576 crc 2e65daaf sha1 78f9bd7f8c40274cf7282892a45e814103944060 ) + rom ( name "Earthworm Jim - Menace 2 the Galaxy (USA, Europe) (GB Compatible).gbc" size 1048576 crc 2e65daaf sha1 78f9bd7f8c40274cf7282892a45e814103944060 flags verified ) ) game ( @@ -35622,6 +37586,12 @@ game ( rom ( name "Elemental Fighter (USA) (Proto).gbc" size 262144 crc 03fc3d03 sha1 92cce7614474d3f9ed9e3fdbd2e2bb434e074565 ) ) +game ( + name "Elementaria - Orientational Waltz (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Elementaria - Orientational Waltz (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Elementaria - Orientational Waltz (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc bffec2e1 sha1 a25cc6ee07e524f9a7121786bd0e513a1c6c2a8d ) +) + game ( name "Elevator Action EX (Europe) (En,Fr,De,Es,It)" description "Elevator Action EX (Europe) (En,Fr,De,Es,It)" @@ -35647,9 +37617,21 @@ game ( ) game ( - name "Emo Cheng DX (Taiwan) (Beta) (Unl)" - description "Emo Cheng DX (Taiwan) (Beta) (Unl)" - rom ( name "Emo Cheng DX (Taiwan) (Beta) (Unl).gbc" size 1048576 crc ebf7bf6e sha1 29b1b595ca8f5ad76ebf4f997d0e4fb8069829f1 ) + name "Emo Cheng DX (Taiwan) (Demo) (Unl)" + description "Emo Cheng DX (Taiwan) (Demo) (Unl)" + rom ( name "Emo Cheng DX (Taiwan) (Demo) (Unl).gbc" size 1048576 crc ebf7bf6e sha1 29b1b595ca8f5ad76ebf4f997d0e4fb8069829f1 ) +) + +game ( + name "Emo Cheng DX (Taiwan) (Unl)" + description "Emo Cheng DX (Taiwan) (Unl)" + rom ( name "Emo Cheng DX (Taiwan) (Unl).gbc" size 4194304 crc 5c388c6d sha1 7919fe7b54a5bc53ebacc13dd338be9e841dadf7 ) +) + +game ( + name "Emo Dao (Taiwan) (Unl)" + description "Emo Dao (Taiwan) (Unl)" + rom ( name "Emo Dao (Taiwan) (Unl).gbc" size 524288 crc 2b2acb79 sha1 929784599694efc6db16163f5bf91e49c2e459fc ) ) game ( @@ -35664,6 +37646,12 @@ game ( rom ( name "Emperor's New Groove, The (USA).gbc" size 2097152 crc 6ebad539 sha1 ba663289bd5d9d09bc8b9ac2c1d38293dcba9c02 ) ) +game ( + name "Empire of Dreams, The (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Empire of Dreams, The (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Empire of Dreams, The (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 9ca3cf6c sha1 d3f4d21bf543431672268b476802693b2da9b6b9 ) +) + game ( name "Equestriad 2001 (Europe) (Proto)" description "Equestriad 2001 (Europe) (Proto)" @@ -35715,19 +37703,25 @@ game ( game ( name "Evel Knievel (USA) (GB Compatible)" description "Evel Knievel (USA) (GB Compatible)" - rom ( name "Evel Knievel (USA) (GB Compatible).gbc" size 2097152 crc 51e951b5 sha1 24cac6ab0151b33d2b1fd06ee01931802fb98267 ) + rom ( name "Evel Knievel (USA) (GB Compatible).gbc" size 2097152 crc 51e951b5 sha1 24cac6ab0151b33d2b1fd06ee01931802fb98267 flags verified ) ) game ( - name "Expiration Date (World) (Aftermarket) (Homebrew)" - description "Expiration Date (World) (Aftermarket) (Homebrew)" - rom ( name "Expiration Date (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 050caa5e sha1 e4b61c220b046e2287272f9b1bef85ad2d835fe3 ) + name "Expiration Date (World) (v1.5) (GB Compatible) (Aftermarket) (Unl)" + description "Expiration Date (World) (v1.5) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Expiration Date (World) (v1.5) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc f222b03b sha1 c14f008cfc182f35fe670e14b57052ae4f8d1c60 ) ) game ( - name "Exploits of Fingers Malone, The (World) (Aftermarket) (Homebrew)" - description "Exploits of Fingers Malone, The (World) (Aftermarket) (Homebrew)" - rom ( name "Exploits of Fingers Malone, The (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 20fe84af sha1 18056b5b032955099c606651f26164de131e54a6 ) + name "Expiration Date (World) (GB Compatible) (Aftermarket) (Unl)" + description "Expiration Date (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Expiration Date (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 050caa5e sha1 e4b61c220b046e2287272f9b1bef85ad2d835fe3 ) +) + +game ( + name "Exploits of Fingers Malone, The (World) (Aftermarket) (Unl)" + description "Exploits of Fingers Malone, The (World) (Aftermarket) (Unl)" + rom ( name "Exploits of Fingers Malone, The (World) (Aftermarket) (Unl).gbc" size 524288 crc 20fe84af sha1 18056b5b032955099c606651f26164de131e54a6 ) ) game ( @@ -35845,15 +37839,57 @@ game ( ) game ( - name "Feng Kuang Da Fu Weng (Taiwan) (Unl)" - description "Feng Kuang Da Fu Weng (Taiwan) (Unl)" - rom ( name "Feng Kuang Da Fu Weng (Taiwan) (Unl).gbc" size 2097152 crc fbf62c35 sha1 7128a6ddbb44ba5ba226516996eb9a6077d365a9 ) + name "Far After (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Far After (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Far After (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc bdaf8f3f sha1 d1ed0fb4d926f4c337399ca342644f89cf00790a ) ) game ( - name "Feng Kuang Da Fu Weng (Taiwan) (Unl) (Alt)" - description "Feng Kuang Da Fu Weng (Taiwan) (Unl) (Alt)" - rom ( name "Feng Kuang Da Fu Weng (Taiwan) (Unl) (Alt).gbc" size 2097152 crc 45b79edc sha1 cc86e1247a352a7c7134db927cc41a1e9950fb96 ) + name "Far After (World) (v1.01) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Far After (World) (v1.01) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Far After (World) (v1.01) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc e61c1dc2 sha1 d7a88a68ec65d9cf3f9521fc9ad9d3f4b51bac5d ) +) + +game ( + name "Featherless Cake Delivery (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + description "Featherless Cake Delivery (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Featherless Cake Delivery (World) (v2.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 63c6c960 sha1 b62ec7a341ea9a0bfe8f0b014da971b73606a86e ) +) + +game ( + name "Featherless Cake Delivery (World) (v1.0) (GB Compatible) (Aftermarket) (Unl)" + description "Featherless Cake Delivery (World) (v1.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Featherless Cake Delivery (World) (v1.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc de373eba sha1 dbf2228017515b407ed9f4a9b3bf01bc2a5f7b0f ) +) + +game ( + name "Feed IT Souls (World) (v1.3) (Aftermarket) (Unl)" + description "Feed IT Souls (World) (v1.3) (Aftermarket) (Unl)" + rom ( name "Feed IT Souls (World) (v1.3) (Aftermarket) (Unl).gbc" size 1048576 crc 701847f5 sha1 aba3fecd55c0cee7fbe49506b367b7e94b56b81c ) +) + +game ( + name "Feed IT Souls (World) (v1.4) (Aftermarket) (Unl)" + description "Feed IT Souls (World) (v1.4) (Aftermarket) (Unl)" + rom ( name "Feed IT Souls (World) (v1.4) (Aftermarket) (Unl).gbc" size 1048576 crc f87760b3 sha1 ea0dd170812d1bcc38de1cabe12a372cd2178c95 ) +) + +game ( + name "Feed The Monster (World) (GB Compatible) (Aftermarket) (Pirate)" + description "Feed The Monster (World) (GB Compatible) (Aftermarket) (Pirate)" + rom ( name "Feed The Monster (World) (GB Compatible) (Aftermarket) (Pirate).gbc" size 524288 crc 7bec6553 sha1 bdcadc0f98d8c9061cbe83c53a047719280b6e09 ) +) + +game ( + name "Fellowship of the Rings (Taiwan) (En) (Unl)" + description "Fellowship of the Rings (Taiwan) (En) (Unl)" + rom ( name "Fellowship of the Rings (Taiwan) (En) (Unl).gbc" size 524288 crc 4bcc59dc sha1 837232bd2eeb50b276049d0908f8ed4dc7efbcfe ) +) + +game ( + name "Feng Kuang A Gei III - Chaoji Zhadan Ren (Taiwan) (Unl)" + description "Feng Kuang A Gei III - Chaoji Zhadan Ren (Taiwan) (Unl)" + rom ( name "Feng Kuang A Gei III - Chaoji Zhadan Ren (Taiwan) (Unl).gbc" size 2097152 crc 8059e009 sha1 84011e3ae407613cfd7b6b1fe85f3812097afc66 flags verified ) ) game ( @@ -35862,6 +37898,18 @@ game ( rom ( name "Feng Zhi Gou II (Taiwan) (Unl).gbc" size 2097152 crc 842cb4fe sha1 4322980e5b21332a71fb7fcadbf57a79aad6346b ) ) +game ( + name "Fengkuang Dafuweng (Taiwan) (Unl)" + description "Fengkuang Dafuweng (Taiwan) (Unl)" + rom ( name "Fengkuang Dafuweng (Taiwan) (Unl).gbc" size 2097152 crc fbf62c35 sha1 7128a6ddbb44ba5ba226516996eb9a6077d365a9 ) +) + +game ( + name "Fengkuang Dafuweng (Taiwan) (Unl) (Alt)" + description "Fengkuang Dafuweng (Taiwan) (Unl) (Alt)" + rom ( name "Fengkuang Dafuweng (Taiwan) (Unl) (Alt).gbc" size 2097152 crc 45b79edc sha1 cc86e1247a352a7c7134db927cc41a1e9950fb96 ) +) + game ( name "Ferret Monogatari (Japan)" description "Ferret Monogatari (Japan)" @@ -35881,33 +37929,39 @@ game ( ) game ( - name "Fillo - Crystal Version (World) (Aftermarket) (Homebrew)" - description "Fillo - Crystal Version (World) (Aftermarket) (Homebrew)" - rom ( name "Fillo - Crystal Version (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 88bb855c sha1 2ffc4199d94f8b29b3f84b7bdb2694154a0bd285 ) + name "Fillo - Crystal Version (World) (Aftermarket) (Unl)" + description "Fillo - Crystal Version (World) (Aftermarket) (Unl)" + rom ( name "Fillo - Crystal Version (World) (Aftermarket) (Unl).gbc" size 524288 crc 88bb855c sha1 2ffc4199d94f8b29b3f84b7bdb2694154a0bd285 ) ) game ( - name "Find Out (World) (Aftermarket) (Homebrew)" - description "Find Out (World) (Aftermarket) (Homebrew)" - rom ( name "Find Out (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 5f8b660e sha1 3605a96f6713157a88e4d88989d2e2f11b9db42f ) + name "Find Out (World) (GB Compatible) (Aftermarket) (Unl)" + description "Find Out (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Find Out (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 5f8b660e sha1 3605a96f6713157a88e4d88989d2e2f11b9db42f ) ) game ( - name "Finders Keepers (World) (Aftermarket) (Homebrew)" - description "Finders Keepers (World) (Aftermarket) (Homebrew)" - rom ( name "Finders Keepers (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 4cfa0cfd sha1 db002f4a2500a9dc98a9ac7c263293d6e4a72cf1 ) + name "Finders Keepers (World) (Aftermarket) (Unl)" + description "Finders Keepers (World) (Aftermarket) (Unl)" + rom ( name "Finders Keepers (World) (Aftermarket) (Unl).gbc" size 524288 crc 4cfa0cfd sha1 db002f4a2500a9dc98a9ac7c263293d6e4a72cf1 ) ) game ( - name "Fire Ant (World) (Aftermarket) (Homebrew)" - description "Fire Ant (World) (Aftermarket) (Homebrew)" - rom ( name "Fire Ant (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 154cc020 sha1 b58ed66838db34fc7f8475ccb670267119d623a5 ) + name "Fire Ant (World) (Aftermarket) (Unl)" + description "Fire Ant (World) (Aftermarket) (Unl)" + rom ( name "Fire Ant (World) (Aftermarket) (Unl).gbc" size 262144 crc 154cc020 sha1 b58ed66838db34fc7f8475ccb670267119d623a5 ) ) game ( - name "Firemen (World) (Aftermarket) (Homebrew)" - description "Firemen (World) (Aftermarket) (Homebrew)" - rom ( name "Firemen (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 7299401f sha1 84c68614334578f866cfa929df736377f04f5d04 ) + name "Fireman Fred (World) (Aftermarket) (Unl)" + description "Fireman Fred (World) (Aftermarket) (Unl)" + rom ( name "Fireman Fred (World) (Aftermarket) (Unl).gbc" size 524288 crc 563d9ca7 sha1 e62a9c6b6a39f0cb662fdb07b72669355b706f57 ) +) + +game ( + name "Firemen (World) (Aftermarket) (Unl)" + description "Firemen (World) (Aftermarket) (Unl)" + rom ( name "Firemen (World) (Aftermarket) (Unl).gbc" size 262144 crc 7299401f sha1 84c68614334578f866cfa929df736377f04f5d04 ) ) game ( @@ -35923,15 +37977,21 @@ game ( ) game ( - name "Fix It Felix Jr. (World) (Aftermarket) (Homebrew)" - description "Fix It Felix Jr. (World) (Aftermarket) (Homebrew)" - rom ( name "Fix It Felix Jr. (World) (Aftermarket) (Homebrew).gbc" size 131072 crc c8014615 sha1 7221f5e53f6027183301d06e258c6cb417007b8c ) + name "Fix It Felix Jr. (World) (GB Compatible) (Aftermarket) (Unl)" + description "Fix It Felix Jr. (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Fix It Felix Jr. (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc c8014615 sha1 7221f5e53f6027183301d06e258c6cb417007b8c ) ) game ( - name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It)" - description "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It)" - rom ( name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc a5b09726 sha1 2f7fb1afedd6c9657715b45397dc5492e40dfe45 flags verified ) + name "Fix My Heart (World) (GB Compo 2021) (GB Compatible) (Aftermarket) (Unl)" + description "Fix My Heart (World) (GB Compo 2021) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Fix My Heart (World) (GB Compo 2021) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 507f9ea2 sha1 28ad64e379dc60d6e1c2617e073f6361c0feb475 flags verified ) +) + +game ( + name "Flashin' (World) (v3.0) (GB Compatible) (Aftermarket) (Unl)" + description "Flashin' (World) (v3.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Flashin' (World) (v3.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc fcc05ec4 sha1 64d31f34e189b3af08bf0c659a93f71dbf83ef71 ) ) game ( @@ -35946,12 +38006,30 @@ game ( rom ( name "Flintstones, The - Burgertime in Bedrock (USA).gbc" size 1048576 crc 14d8cc5d sha1 065851358f6720d4926faa42b015da68cafa6c28 ) ) +game ( + name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It)" + description "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It)" + rom ( name "Flintstones, The - Burgertime in Bedrock (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc a5b09726 sha1 2f7fb1afedd6c9657715b45397dc5492e40dfe45 flags verified ) +) + game ( name "Flipper & Lopaka (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" description "Flipper & Lopaka (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da)" rom ( name "Flipper & Lopaka (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da).gbc" size 1048576 crc 08b9e4aa sha1 3d538b78ef5f1238f47531c069921056b00e33b3 ) ) +game ( + name "Flooder (World) (Aftermarket) (Unl)" + description "Flooder (World) (Aftermarket) (Unl)" + rom ( name "Flooder (World) (Aftermarket) (Unl).gbc" size 32768 crc 253dcbe0 sha1 8fdcd8b02604ac5259fb6aa80e5ba67a03c861fb ) +) + +game ( + name "Flooder (World) (Anniversary Edition) (Aftermarket) (Unl)" + description "Flooder (World) (Anniversary Edition) (Aftermarket) (Unl)" + rom ( name "Flooder (World) (Anniversary Edition) (Aftermarket) (Unl).gbc" size 32768 crc cdda76f8 sha1 e5eec8efc032aa5bce1826f7b6b8790c61c96e06 ) +) + game ( name "Floracy (Europe) (Proto) (2000-10-10)" description "Floracy (Europe) (Proto) (2000-10-10)" @@ -35965,9 +38043,15 @@ game ( ) game ( - name "Formula One 2000 (USA)" - description "Formula One 2000 (USA)" - rom ( name "Formula One 2000 (USA).gbc" size 1048576 crc 703c057f sha1 7a38195842e536581fdcea42e4ebe50967581736 ) + name "Forest of Fallen Knights (World) (GB Compatible) (Aftermarket) (Unl)" + description "Forest of Fallen Knights (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Forest of Fallen Knights (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc fa2d92a1 sha1 24f02d116aafb7b55d6cfd6d263b7595986af843 ) +) + +game ( + name "Forest of Fallen Knights (World) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Forest of Fallen Knights (World) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Forest of Fallen Knights (World) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 4c21e563 sha1 f6f84f1a44d41fa7d26a9195ddf791fae53dfcdf ) ) game ( @@ -35976,6 +38060,12 @@ game ( rom ( name "Formula One 2000 (Europe) (En,Fr,De,Es,It) (Proto).gbc" size 1048576 crc e689bf16 sha1 7aa7073b7b494522f7cfcd268aa066b7fe52c671 ) ) +game ( + name "Formula One 2000 (USA)" + description "Formula One 2000 (USA)" + rom ( name "Formula One 2000 (USA).gbc" size 1048576 crc 703c057f sha1 7a38195842e536581fdcea42e4ebe50967581736 ) +) + game ( name "Fort Boyard (Europe) (En,Fr,De,Es,It,Nl,Pt)" description "Fort Boyard (Europe) (En,Fr,De,Es,It,Nl,Pt)" @@ -35988,6 +38078,24 @@ game ( rom ( name "Freestyle Scooter (Europe).gbc" size 1048576 crc ee79117d sha1 cf6ae174584bbfb5ae30478841114443adc00245 ) ) +game ( + name "Friday the 13th - The GB Game (World) (GB Compatible) (Aftermarket) (Unl)" + description "Friday the 13th - The GB Game (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Friday the 13th - The GB Game (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 7543586a sha1 397821751ac6464582f61566f3a7c731a46b24ba ) +) + +game ( + name "Friendly Fire (World) (Aftermarket) (Unl)" + description "Friendly Fire (World) (Aftermarket) (Unl)" + rom ( name "Friendly Fire (World) (Aftermarket) (Unl).gbc" size 262144 crc 5c6dca2b sha1 8f8085010e28aa8bdb312d086b0002b706742282 ) +) + +game ( + name "Friendly Fire (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl)" + description "Friendly Fire (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Friendly Fire (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc d8be10d6 sha1 d09f4d2f799ac2e2731be0171625846d28d0f57e ) +) + game ( name "Frogger (USA) (Rev 2) (GB Compatible)" description "Frogger (USA) (Rev 2) (GB Compatible)" @@ -36024,6 +38132,12 @@ game ( rom ( name "Frogger 2 (USA) (Rev 1).gbc" size 1048576 crc e3227b7d sha1 0d5028ca6fcc10df46d11cd4b56e5add1dc5e63e ) ) +game ( + name "From Below Pocket (World) (Aftermarket) (Unl)" + description "From Below Pocket (World) (Aftermarket) (Unl)" + rom ( name "From Below Pocket (World) (Aftermarket) (Unl).gbc" size 131072 crc 35ad9b5a sha1 c0e072bfb88c84dc68b2eded1f9c088d75ffa5ed ) +) + game ( name "From TV Animation One Piece - Maboroshi no Grand Line Boukenki! (Japan) (Beta 1) (SGB Enhanced) (GB Compatible)" description "From TV Animation One Piece - Maboroshi no Grand Line Boukenki! (Japan) (Beta 1) (SGB Enhanced) (GB Compatible)" @@ -36066,6 +38180,12 @@ game ( rom ( name "Front Row (Japan).gbc" size 1048576 crc 6eea9243 sha1 64c8a9459d7c80e297774dab7775b5edf59432cc ) ) +game ( + name "Fugazim (World) (Pt) (GB Compatible) (Aftermarket) (Unl)" + description "Fugazim (World) (Pt) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Fugazim (World) (Pt) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 85edfba4 sha1 8a95571a32c5a23bd6be4edf6429f630d7a1a15a ) +) + game ( name "Full Time Soccer (Europe) (Unl)" description "Full Time Soccer (Europe) (Unl)" @@ -36078,6 +38198,12 @@ game ( rom ( name "Full Time Soccer & Hang Time Basketball (Europe) (Unl).gbc" size 524288 crc 0634c196 sha1 aefb746984b3450b90bbfaa5de21a252685ddabb ) ) +game ( + name "Fury (World) (Aftermarket) (Unl)" + description "Fury (World) (Aftermarket) (Unl)" + rom ( name "Fury (World) (Aftermarket) (Unl).gbc" size 262144 crc 7217c41d sha1 ef532b587eb438f1a39a77086ac0b8bbae23a16d ) +) + game ( name "Fushigi no Dungeon - Fuurai no Shiren GB 2 - Sabaku no Majou (Japan) (AFMJ)" description "Fushigi no Dungeon - Fuurai no Shiren GB 2 - Sabaku no Majou (Japan) (AFMJ)" @@ -36091,9 +38217,15 @@ game ( ) game ( - name "G-Man (World) (Aftermarket) (Homebrew)" - description "G-Man (World) (Aftermarket) (Homebrew)" - rom ( name "G-Man (World) (Aftermarket) (Homebrew).gbc" size 524288 crc ff3beab1 sha1 cb9486ca9a6ad3903662963aa966145257ef92a6 ) + name "G-Man (World) (Aftermarket) (Unl)" + description "G-Man (World) (Aftermarket) (Unl)" + rom ( name "G-Man (World) (Aftermarket) (Unl).gbc" size 524288 crc ff3beab1 sha1 cb9486ca9a6ad3903662963aa966145257ef92a6 ) +) + +game ( + name "G.B Corp. (World) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "G.B Corp. (World) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "G.B Corp. (World) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc fd2e40f4 sha1 e442316132506ff223a9e5f33d874b71ec09d71a flags verified ) ) game ( @@ -36109,9 +38241,9 @@ game ( ) game ( - name "Gakkyuu Ou Yamazaki (Japan) (GB Compatible)" - description "Gakkyuu Ou Yamazaki (Japan) (GB Compatible)" - rom ( name "Gakkyuu Ou Yamazaki (Japan) (GB Compatible).gbc" size 1048576 crc b8147b5c sha1 132b872391565d418ccc9d0e1c643510d778c066 ) + name "Gakkyuu Ou Yamazaki (Japan) (Possible Proto) (GB Compatible)" + description "Gakkyuu Ou Yamazaki (Japan) (Possible Proto) (GB Compatible)" + rom ( name "Gakkyuu Ou Yamazaki (Japan) (Possible Proto) (GB Compatible).gbc" size 1048576 crc b8147b5c sha1 132b872391565d418ccc9d0e1c643510d778c066 ) ) game ( @@ -36144,6 +38276,12 @@ game ( rom ( name "Game & Watch Gallery 3 (USA, Europe) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 1ac625da sha1 64ccb3b41715080a9aa13970678aa9047fc7a9fd flags verified ) ) +game ( + name "Game Boy Camera Gallery 2022, The (World) (GB Compatible) (Aftermarket) (Unl)" + description "Game Boy Camera Gallery 2022, The (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Game Boy Camera Gallery 2022, The (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc f1948966 sha1 14849ab5831c71949ec3a1fe7657050057d2cf29 ) +) + game ( name "Game Boy Color (World) (Demo) (Kiosk)" description "Game Boy Color (World) (Demo) (Kiosk)" @@ -36151,9 +38289,9 @@ game ( ) game ( - name "Game Boy Gallery 2 (Japan) (SGB Enhanced, GB Compatible) (NP)" - description "Game Boy Gallery 2 (Japan) (SGB Enhanced, GB Compatible) (NP)" - rom ( name "Game Boy Gallery 2 (Japan) (SGB Enhanced, GB Compatible) (NP).gbc" size 1048576 crc e99beba5 sha1 90a9b368bca0f47fe72028ff4d50fb3d3060c32f ) + name "Game Boy Gallery 2 (Japan) (Possible Proto) (SGB Enhanced, GB Compatible) (NP)" + description "Game Boy Gallery 2 (Japan) (Possible Proto) (SGB Enhanced, GB Compatible) (NP)" + rom ( name "Game Boy Gallery 2 (Japan) (Possible Proto) (SGB Enhanced, GB Compatible) (NP).gbc" size 1048576 crc e99beba5 sha1 90a9b368bca0f47fe72028ff4d50fb3d3060c32f ) ) game ( @@ -36199,15 +38337,15 @@ game ( ) game ( - name "Gamer Boy Mission (World) (Aftermarket) (Homebrew)" - description "Gamer Boy Mission (World) (Aftermarket) (Homebrew)" - rom ( name "Gamer Boy Mission (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 96721e5d sha1 90fad94433a5b0dbcf73f4a2d4ebb75d7ab065c4 ) + name "Gamer Boy Mission (World) (GB Compatible) (Aftermarket) (Unl)" + description "Gamer Boy Mission (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Gamer Boy Mission (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 96721e5d sha1 90fad94433a5b0dbcf73f4a2d4ebb75d7ab065c4 ) ) game ( - name "Gamer Boy Mission (World) (Demo) (Aftermarket) (Homebrew)" - description "Gamer Boy Mission (World) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Gamer Boy Mission (World) (Demo) (Aftermarket) (Homebrew).gbc" size 262144 crc a02d2ae2 sha1 7eb6865c5c265193763ec0bf751d26964e870120 ) + name "Gamer Boy Mission (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Gamer Boy Mission (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Gamer Boy Mission (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc a02d2ae2 sha1 7eb6865c5c265193763ec0bf751d26964e870120 ) ) game ( @@ -36282,10 +38420,82 @@ game ( rom ( name "GB Memory Multi Menu (Japan) (SGB Enhanced, GB Compatible) (NP).gbc" size 131072 crc ec823cc1 sha1 0781eaecb7fd25c068e396b5eb02c6231baf6ea3 ) ) +game ( + name "GB-Wordyl (World) (Pt-BR) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Pt-BR) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Pt-BR) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc f20c0097 sha1 691af25434a09931a302ced52c757d28b9b06619 ) +) + +game ( + name "GB-Wordyl (World) (Ca) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Ca) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Ca) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 164999eb sha1 197d3d194d4cb6cae9a358f7fb53d6de649e7c5f ) +) + +game ( + name "GB-Wordyl (World) (De) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (De) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (De) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 60b075d1 sha1 0a66254b2327b48657de64d6102ac05f1e8700e7 ) +) + +game ( + name "GB-Wordyl (World) (Es) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Es) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Es) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 1a169897 sha1 0636b968e8e24fe7c1910f61db6e94fa84824494 ) +) + +game ( + name "GB-Wordyl (World) (Fr) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Fr) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Fr) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 593965ff sha1 75d566045a680aaed4d40b83b6418cbfab5b4422 ) +) + +game ( + name "GB-Wordyl (World) (It) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (It) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (It) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc d81ab567 sha1 1dfd3c4508ffb6598662bcf1b16ec109a9282dd5 ) +) + +game ( + name "GB-Wordyl (World) (Kw) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Kw) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Kw) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc f795689c sha1 9a332127182e8155d1a3dc53e1382a6c9dde6aeb ) +) + +game ( + name "GB-Wordyl (World) (Es-XL) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Es-XL) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Es-XL) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 660ed37b sha1 0792fbef010cac21c12cbcb8b3c85b3af30faec4 ) +) + +game ( + name "GB-Wordyl (World) (Nl) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (Nl) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (Nl) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 6dc4faaa sha1 7617083f9b13b2f95bdf1b0b327ffb4f8ccbe3c9 ) +) + +game ( + name "GB-Wordyl (World) (En) (GB Compatible) (Aftermarket) (Unl)" + description "GB-Wordyl (World) (En) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "GB-Wordyl (World) (En) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 8780e125 sha1 7163bfbaa2cae2f9d41c472128f69a4fa5879180 ) +) + +game ( + name "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl) (Alt)" + description "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl) (Alt)" + rom ( name "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl) (Alt).gbc" size 1048576 crc c0ac1b50 sha1 4dcef6fcfe009e17da0bb13e50e7410a3f586e23 ) +) + game ( name "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl)" description "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl)" - rom ( name "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl).gbc" size 1048576 crc c0ac1b50 sha1 4dcef6fcfe009e17da0bb13e50e7410a3f586e23 ) + rom ( name "Gedou Jian Shen - Soul Falchion (Taiwan) (Unl).gbc" size 1048576 crc 1b1c6f68 sha1 fd06c62b42878e8094e610b180c1848c785f67e9 ) +) + +game ( + name "Gedou Zhizun 2003 (Taiwan) (Unl)" + description "Gedou Zhizun 2003 (Taiwan) (Unl)" + rom ( name "Gedou Zhizun 2003 (Taiwan) (Unl).gbc" size 1048576 crc f7630d88 sha1 f43c4055f69a1ff6b325494b5b34c8043914cd9d ) ) game ( @@ -36343,9 +38553,27 @@ game ( ) game ( - name "Ghost Town (World) (Aftermarket) (Homebrew)" - description "Ghost Town (World) (Aftermarket) (Homebrew)" - rom ( name "Ghost Town (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 52efcc35 sha1 1a4a7846d6c87f0bd8b267aa6a8aa98e797fedf8 ) + name "Ghost of the Arcade (World) (v1.7) (Aftermarket) (Unl)" + description "Ghost of the Arcade (World) (v1.7) (Aftermarket) (Unl)" + rom ( name "Ghost of the Arcade (World) (v1.7) (Aftermarket) (Unl).gbc" size 1048576 crc 4aa9a9c2 sha1 ac697bc27a126c1389e6bef94a2c83404e8819f2 ) +) + +game ( + name "Ghost of the Arcade (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + description "Ghost of the Arcade (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ghost of the Arcade (World) (v1.3) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 32e2ea48 sha1 ee11d5397316b69eee5ae3023de08c3b919c93df ) +) + +game ( + name "Ghost of the Arcade (World) (GB Compo 2023) (GB Compatible) (Aftermarket) (Unl)" + description "Ghost of the Arcade (World) (GB Compo 2023) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ghost of the Arcade (World) (GB Compo 2023) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc ea87ad5d sha1 433e25df1421e77cdc807296e1ed662d9e43d685 ) +) + +game ( + name "Ghost Town (World) (Aftermarket) (Unl)" + description "Ghost Town (World) (Aftermarket) (Unl)" + rom ( name "Ghost Town (World) (Aftermarket) (Unl).gbc" size 262144 crc 52efcc35 sha1 1a4a7846d6c87f0bd8b267aa6a8aa98e797fedf8 ) ) game ( @@ -36402,6 +38630,12 @@ game ( rom ( name "Gobs of Games (USA) (En,Fr,De).gbc" size 1048576 crc 2e61c391 sha1 89695361ccbca372662f6634678a40ea676076a7 ) ) +game ( + name "Gods of the Universe (World) (Aftermarket) (Unl)" + description "Gods of the Universe (World) (Aftermarket) (Unl)" + rom ( name "Gods of the Universe (World) (Aftermarket) (Unl).gbc" size 262144 crc 27b87354 sha1 74eb8cd698097290b93fb08d9b19486d05411877 ) +) + game ( name "Godzilla - The Series (Europe) (En,Fr,De) (GB Compatible)" description "Godzilla - The Series (Europe) (En,Fr,De) (GB Compatible)" @@ -36486,6 +38720,12 @@ game ( rom ( name "Goraku Ou Tango! (Japan) (GB Compatible).gbc" size 1048576 crc 81fb43e1 sha1 1d49232763c1422a00cbb893d0f900c44a2ccf54 ) ) +game ( + name "Gorf the Ghost Saves Halloween (World) (GB Compatible) (Aftermarket) (Unl)" + description "Gorf the Ghost Saves Halloween (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Gorf the Ghost Saves Halloween (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc ab10cec6 sha1 9dcaa6824fab806683737bdf1c76609c68c451a5 ) +) + game ( name "Grand Casino (Japan) (Proto)" description "Grand Casino (Japan) (Proto)" @@ -36534,6 +38774,24 @@ game ( rom ( name "Granduel - Shinki Dungeon no Hihou (Japan) (Sample).gbc" size 2097152 crc 7122136d sha1 534fc9ae5800eb935460f145e1bbc57f77ab2555 ) ) +game ( + name "Grave Encounter, A (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + description "Grave Encounter, A (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Grave Encounter, A (World) (v1.3) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc a5ad3c0b sha1 1cf0cf6d1da5c5337856ecc0a60d2e9fb3c98f58 ) +) + +game ( + name "Grave Encounter, A (World) (v1.21) (GB Compatible) (Aftermarket) (Unl)" + description "Grave Encounter, A (World) (v1.21) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Grave Encounter, A (World) (v1.21) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc b29fc03f sha1 2f979202a4bf4f98f3026a7548a8b6c7008806bf ) +) + +game ( + name "Gravitorque (World) (GB Compatible) (Aftermarket) (Unl)" + description "Gravitorque (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Gravitorque (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc a0e998e1 sha1 ab656383e9aaaa2991aa344bdc8f21370f0eda36 ) +) + game ( name "Great Battle Pocket, The (Japan) (SGB Enhanced) (GB Compatible)" description "Great Battle Pocket, The (Japan) (SGB Enhanced) (GB Compatible)" @@ -36570,6 +38828,54 @@ game ( rom ( name "Gremlins - Unleashed (Europe) (En,Fr,De,Es,It,Pt) (Beta).gbc" size 1048576 crc c38d52e7 sha1 675623b58fa0d307355c77d7a4783af7927681e9 ) ) +game ( + name "Grimace's Birthday (World) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (Aftermarket) (Unl).gbc" size 1048576 crc 7f4386e9 sha1 d6358d100ea65d34d95588f800635b64927baf82 ) +) + +game ( + name "Grimace's Birthday (World) (v1.1) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.1) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.1) (Aftermarket) (Unl).gbc" size 1048576 crc 7744f551 sha1 035b7417e03c4e264a90212f2a3811012f03c2a2 flags verified ) +) + +game ( + name "Grimace's Birthday (World) (v1.2) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.2) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.2) (Aftermarket) (Unl).gbc" size 1048576 crc 9dee42fe sha1 071fa179df96950c3c92b0abbe32092b1816ec40 flags verified ) +) + +game ( + name "Grimace's Birthday (World) (v1.4) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.4) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.4) (Aftermarket) (Unl).gbc" size 1048576 crc 9baa5f46 sha1 d247c03119ac14f97fdeeaa6bf0defa98e35fa17 flags verified ) +) + +game ( + name "Grimace's Birthday (World) (v1.3) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.3) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.3) (Aftermarket) (Unl).gbc" size 1048576 crc ab41a9ef sha1 d8e727745e285f5e467f5eccbfd30ee175bafc2e flags verified ) +) + +game ( + name "Grimace's Birthday (World) (v1.5) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.5) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.5) (Aftermarket) (Unl).gbc" size 1048576 crc f8e8e1f3 sha1 a3fdfe3981e800fa7c73ff989bc06426f668c331 flags verified ) +) + +game ( + name "Grimace's Birthday (World) (v1.6) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.6) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.6) (Aftermarket) (Unl).gbc" size 1048576 crc a7b59d7b sha1 295fdc3218d1699dea6d5832d068b721fccf9bd4 flags verified ) +) + +game ( + name "Grimace's Birthday (World) (v1.7) (Aftermarket) (Unl)" + description "Grimace's Birthday (World) (v1.7) (Aftermarket) (Unl)" + rom ( name "Grimace's Birthday (World) (v1.7) (Aftermarket) (Unl).gbc" size 1048576 crc f3879ef0 sha1 27d7ee2f31bf575185711217c3cc9e08cbc5928a flags verified ) +) + game ( name "Grinch (Japan)" description "Grinch (Japan)" @@ -36589,27 +38895,33 @@ game ( ) game ( - name "Gu Huo Lang II 2003 (Taiwan) (Unl)" - description "Gu Huo Lang II 2003 (Taiwan) (Unl)" - rom ( name "Gu Huo Lang II 2003 (Taiwan) (Unl).gbc" size 2097152 crc 74d71b0c sha1 fcbb769de0896ae69fe1063fa5d87cf079c8606a ) + name "Guaishou Go! Go! II (Taiwan) (Unl)" + description "Guaishou Go! Go! II (Taiwan) (Unl)" + rom ( name "Guaishou Go! Go! II (Taiwan) (Unl).gbc" size 1048576 crc b0237467 sha1 8ed6f39a9973d634266806455ef845b6bdb5ab95 ) ) game ( - name "Guai Shou Go! Go! II (Taiwan)" - description "Guai Shou Go! Go! II (Taiwan)" - rom ( name "Guai Shou Go! Go! II (Taiwan).gbc" size 1048576 crc b0237467 sha1 8ed6f39a9973d634266806455ef845b6bdb5ab95 ) + name "Guiwu Zhe 2 (Taiwan) (Unl)" + description "Guiwu Zhe 2 (Taiwan) (Unl)" + rom ( name "Guiwu Zhe 2 (Taiwan) (Unl).gbc" size 2097152 crc 955bc6ad sha1 5fe41ac064f4b4d4476ef4177a2f4d69fae1a933 ) ) game ( - name "Gui Wu Zhe 2 (Taiwan) (Unl)" - description "Gui Wu Zhe 2 (Taiwan) (Unl)" - rom ( name "Gui Wu Zhe 2 (Taiwan) (Unl).gbc" size 2097152 crc 955bc6ad sha1 5fe41ac064f4b4d4476ef4177a2f4d69fae1a933 ) + name "Gun Law (World) (Aftermarket) (Unl)" + description "Gun Law (World) (Aftermarket) (Unl)" + rom ( name "Gun Law (World) (Aftermarket) (Unl).gbc" size 262144 crc 3a0b6823 sha1 c49f7e0a5055f836528a7bc0cb6f45f221c76475 ) ) game ( - name "Gun Law (World) (Aftermarket) (Homebrew)" - description "Gun Law (World) (Aftermarket) (Homebrew)" - rom ( name "Gun Law (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 3a0b6823 sha1 c49f7e0a5055f836528a7bc0cb6f45f221c76475 ) + name "Gunslinger (World) (Aftermarket) (Unl)" + description "Gunslinger (World) (Aftermarket) (Unl)" + rom ( name "Gunslinger (World) (Aftermarket) (Unl).gbc" size 262144 crc 0dfd765f sha1 8410ef1558649f9badc71629827ba1500510d221 ) +) + +game ( + name "Gunther the Monster and His Friends (World) (Aftermarket) (Unl)" + description "Gunther the Monster and His Friends (World) (Aftermarket) (Unl)" + rom ( name "Gunther the Monster and His Friends (World) (Aftermarket) (Unl).gbc" size 524288 crc 2d9b59bf sha1 d89fe1cd97d1ef2c457aa90b1c00e7b473c57270 ) ) game ( @@ -36630,6 +38942,12 @@ game ( rom ( name "Gute Zeiten Schlechte Zeiten Quiz (Germany) (GB Compatible).gbc" size 1048576 crc 5f13a2d4 sha1 611d8ab71bdeb6b0fd292118676e85e940d11bd4 ) ) +game ( + name "Guzzler (World) (Aftermarket) (Unl)" + description "Guzzler (World) (Aftermarket) (Unl)" + rom ( name "Guzzler (World) (Aftermarket) (Unl).gbc" size 524288 crc 3684abd0 sha1 e36cd02fe2b697901843c4cbf6d83da8a9b7b923 ) +) + game ( name "Gyouten Ningen Batseelor - Doctor Guy no Yabou (Japan)" description "Gyouten Ningen Batseelor - Doctor Guy no Yabou (Japan)" @@ -36637,27 +38955,9 @@ game ( ) game ( - name "Ha Li Bo Te 2 - Xiao Shi De Mi Shi 2003 (Taiwan) (Unl)" - description "Ha Li Bo Te 2 - Xiao Shi De Mi Shi 2003 (Taiwan) (Unl)" - rom ( name "Ha Li Bo Te 2 - Xiao Shi De Mi Shi 2003 (Taiwan) (Unl).gbc" size 2097152 crc 1b3e1243 sha1 0829cbcab3ef5d03c94d5efe769f4f4a93ac47fa ) -) - -game ( - name "Ha Li Xiao Zi Di Er Bu - Mi Shi De Mi (Taiwan) (Unl)" - description "Ha Li Xiao Zi Di Er Bu - Mi Shi De Mi (Taiwan) (Unl)" - rom ( name "Ha Li Xiao Zi Di Er Bu - Mi Shi De Mi (Taiwan) (Unl).gbc" size 2097152 crc 859457c8 sha1 3844b61eb455507d634ee7048dc8c9e64216fffe ) -) - -game ( - name "Ha Li Xiao Zi IV 2003 (Taiwan) (Unl)" - description "Ha Li Xiao Zi IV 2003 (Taiwan) (Unl)" - rom ( name "Ha Li Xiao Zi IV 2003 (Taiwan) (Unl).gbc" size 2097152 crc db3c8b95 sha1 0d230b20388f4396d6345b8eb59f54fc169ad8ee ) -) - -game ( - name "Hai Zhan Qi Bing (Taiwan) (Unl)" - description "Hai Zhan Qi Bing (Taiwan) (Unl)" - rom ( name "Hai Zhan Qi Bing (Taiwan) (Unl).gbc" size 2097152 crc a962ad73 sha1 36f6454e3e70bb29f27782f2ec4200d5aef5ca98 ) + name "Haizhan Qibing (Taiwan) (Unl)" + description "Haizhan Qibing (Taiwan) (Unl)" + rom ( name "Haizhan Qibing (Taiwan) (Unl).gbc" size 2097152 crc a962ad73 sha1 36f6454e3e70bb29f27782f2ec4200d5aef5ca98 ) ) game ( @@ -36666,12 +38966,24 @@ game ( rom ( name "Hajimari no Mori (Japan) (Proto).gbc" size 2097152 crc fecc8ee8 sha1 75a3e1794fd6bd6d35f0a357a82612c016dfba24 ) ) +game ( + name "Hali Xiaozi Dier Bu - Mishi de Mi (Taiwan) (Unl)" + description "Hali Xiaozi Dier Bu - Mishi de Mi (Taiwan) (Unl)" + rom ( name "Hali Xiaozi Dier Bu - Mishi de Mi (Taiwan) (Unl).gbc" size 2097152 crc 859457c8 sha1 3844b61eb455507d634ee7048dc8c9e64216fffe ) +) + game ( name "Halloween Racer (Europe) (En,Fr,De,Es,It,Pt)" description "Halloween Racer (Europe) (En,Fr,De,Es,It,Pt)" rom ( name "Halloween Racer (Europe) (En,Fr,De,Es,It,Pt).gbc" size 1048576 crc 70f3b431 sha1 15bf27a7847817fbbb9cb7729b8046a6d70164c5 ) ) +game ( + name "Halo - Combat Devolved (World) (GB Compatible) (Aftermarket) (Unl)" + description "Halo - Combat Devolved (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Halo - Combat Devolved (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc c7297c31 sha1 c38cc0e80a2e04693e3a86574c03f23f3e472c88 flags verified ) +) + game ( name "Hamster Club (Japan) (GB Compatible)" description "Hamster Club (Japan) (GB Compatible)" @@ -36744,6 +39056,18 @@ game ( rom ( name "Hamtaro - Ham-Hams Unite! (USA).gbc" size 2097152 crc 1271117f sha1 9770bf59e932b41882839ce9eec033f576094fee flags verified ) ) +game ( + name "Hamtaro - Ham-Hams Unite! (USA) (2002-08-07) (Beta)" + description "Hamtaro - Ham-Hams Unite! (USA) (2002-08-07) (Beta)" + rom ( name "Hamtaro - Ham-Hams Unite! (USA) (2002-08-07) (Beta).gbc" size 2097152 crc d0cf0d86 sha1 c85ba2da0a652544f938439c8826c5c6754f5e75 ) +) + +game ( + name "Hamtaro - Ham-Hams Unite! (Europe) (En,Fr,De,Es,It) (2002-11-11) (Beta)" + description "Hamtaro - Ham-Hams Unite! (Europe) (En,Fr,De,Es,It) (2002-11-11) (Beta)" + rom ( name "Hamtaro - Ham-Hams Unite! (Europe) (En,Fr,De,Es,It) (2002-11-11) (Beta).gbc" size 4194304 crc 816b0325 sha1 17c3ff0da5b9733a768ee53eccd13059fda16116 ) +) + game ( name "Hamunaptra - Ushinawareta Sabaku no Miyako (Japan)" description "Hamunaptra - Ushinawareta Sabaku no Miyako (Japan)" @@ -36774,6 +39098,12 @@ game ( rom ( name "Hang Time Basketball (Europe) (Unl).gbc" size 262144 crc 3207b7d9 sha1 340201c045c020be6de3504fdecbce1ff07a2139 ) ) +game ( + name "Harbour Attack (World) (Aftermarket) (Unl)" + description "Harbour Attack (World) (Aftermarket) (Unl)" + rom ( name "Harbour Attack (World) (Aftermarket) (Unl).gbc" size 262144 crc 7455782e sha1 1d0b3779007ba8f34e11b189552955dbf5c75a28 ) +) + game ( name "Harley-Davidson Motor Cycles - Race Across America (USA)" description "Harley-Davidson Motor Cycles - Race Across America (USA)" @@ -36804,12 +39134,6 @@ game ( rom ( name "Harry Potter 3 - Shen Qi Zhi Guang Lun (Taiwan) (Unl).gbc" size 524288 crc aa83a110 sha1 7e572f24a302902cd78b238be5732d838bada7b2 ) ) -game ( - name "Harry Potter 3 2003 (Taiwan) (Unl)" - description "Harry Potter 3 2003 (Taiwan) (Unl)" - rom ( name "Harry Potter 3 2003 (Taiwan) (Unl).gbc" size 1048576 crc 4ea2c869 sha1 739c0e5dc0efd4ddb912236a6f630c3d6987d064 ) -) - game ( name "Harry Potter and the Chamber of Secrets (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,Da)" description "Harry Potter and the Chamber of Secrets (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,Da)" @@ -36817,9 +39141,9 @@ game ( ) game ( - name "Harry Potter and the Sorcerer's Stone (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" - description "Harry Potter and the Sorcerer's Stone (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" - rom ( name "Harry Potter and the Sorcerer's Stone (Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi).gbc" size 4194304 crc 4fd8b7c5 sha1 4e6f676ec15e0e6238cb81853b5a74bbb20657a1 ) + name "Harry Potter and the Sorcerer's Stone (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + description "Harry Potter and the Sorcerer's Stone (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi)" + rom ( name "Harry Potter and the Sorcerer's Stone (USA, Europe) (En,Fr,De,Es,It,Nl,Pt,Sv,No,Da,Fi).gbc" size 4194304 crc 4fd8b7c5 sha1 4e6f676ec15e0e6238cb81853b5a74bbb20657a1 flags verified ) ) game ( @@ -36877,9 +39201,33 @@ game ( ) game ( - name "He Jin Zhuang Bei II (Taiwan) (Unl)" - description "He Jin Zhuang Bei II (Taiwan) (Unl)" - rom ( name "He Jin Zhuang Bei II (Taiwan) (Unl).gbc" size 2097152 crc ef4bbb34 sha1 6a15fc7dbb3b9d7c130b9a25b568d39c655d68ca ) + name "Haunted (World) (GB Compatible) (Aftermarket) (Unl)" + description "Haunted (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Haunted (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 4b3670bd sha1 f245b8e21716a400769488b852f15d276f3549a6 ) +) + +game ( + name "Hauntsfield (World) (GB Compatible) (Aftermarket) (Unl)" + description "Hauntsfield (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Hauntsfield (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 287afc75 sha1 42ccc76883c041bc5c6c25a2e61ccc939c14811f ) +) + +game ( + name "Hauntsfield (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + description "Hauntsfield (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Hauntsfield (World) (v2.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 6e484d6a sha1 7282ef5cc2354345c8832b4dde66a559de74f73f ) +) + +game ( + name "Heebie Jeebies (World) (Aftermarket) (Unl)" + description "Heebie Jeebies (World) (Aftermarket) (Unl)" + rom ( name "Heebie Jeebies (World) (Aftermarket) (Unl).gbc" size 262144 crc 73762d53 sha1 d427f18cb854e1387d93c19b88cb7193975e6472 ) +) + +game ( + name "Hejin Zhuangbei II (Taiwan) (Unl)" + description "Hejin Zhuangbei II (Taiwan) (Unl)" + rom ( name "Hejin Zhuangbei II (Taiwan) (Unl).gbc" size 2097152 crc ef4bbb34 sha1 6a15fc7dbb3b9d7c130b9a25b568d39c655d68ca ) ) game ( @@ -36973,9 +39321,28 @@ game ( ) game ( - name "High Noon (World) (Aftermarket) (Homebrew)" - description "High Noon (World) (Aftermarket) (Homebrew)" - rom ( name "High Noon (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 1d00e48d sha1 21d5e871ed009a674659344d3d768fb2389c0d04 ) + name "Hidden Gems (World) (GB Compatible) (Aftermarket) (Unl)" + description "Hidden Gems (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Hidden Gems (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 6f430dda sha1 e0cfe038063b1cd601a5f1b5af047efc705a7aaa ) +) + +game ( + name "High Noon (World) (Aftermarket) (Unl)" + description "High Noon (World) (Aftermarket) (Unl)" + rom ( name "High Noon (World) (Aftermarket) (Unl).gbc" size 262144 crc 1d00e48d sha1 21d5e871ed009a674659344d3d768fb2389c0d04 ) +) + +game ( + name "Hime's Quest (World) (Digital) (Aftermarket) (Unl)" + description "Hime's Quest (World) (Digital) (Aftermarket) (Unl)" + rom ( name "Hime's Quest (World) (Digital) (Aftermarket) (Unl).gbc" size 2097152 crc de5c21c2 sha1 7b6672c46c23aaa282bd4fded0713c6dfae2eb66 ) +) + +game ( + name "Hime's Quest (World) (Cart) (Aftermarket) (Unl)" + description "Hime's Quest (World) (Cart) (Aftermarket) (Unl)" + rom ( name "Hime's Quest (World) (Cart) (Aftermarket) (Unl).gbc" size 2097152 crc 546f578a sha1 ff90ca3ec7fb5d02865ae3cfd807ad3541dd21fc ) + rom ( name "Hime's Quest (World) (Cart) (Aftermarket) (Unl) (Factory Save).sav" size 32768 crc d5ed60c7 sha1 8d6c2e9da87837ba16bbd07247a91a0c3050d2fe ) ) game ( @@ -37038,6 +39405,12 @@ game ( rom ( name "Honkaku Yonin Uchi Mahjong - Mahjong Ou (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 8ed4bbba sha1 222487f14aaaa8f0bb536a09238e63ac95636208 ) ) +game ( + name "Host, The (World) (Aftermarket) (Unl)" + description "Host, The (World) (Aftermarket) (Unl)" + rom ( name "Host, The (World) (Aftermarket) (Unl).gbc" size 524288 crc 5f783000 sha1 05cc1f1e52167c6985ebb0a3e67af1fc2fbff93c ) +) + game ( name "Hot Wheels - Stunt Track Driver (USA, Europe) (SGB Enhanced) (GB Compatible)" description "Hot Wheels - Stunt Track Driver (USA, Europe) (SGB Enhanced) (GB Compatible)" @@ -37057,9 +39430,9 @@ game ( ) game ( - name "Hugo (World) (Aftermarket) (Homebrew)" - description "Hugo (World) (Aftermarket) (Homebrew)" - rom ( name "Hugo (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 6581c78a sha1 390d2665f34ceaa5e34cc9f8f7c26d9e7583a92b ) + name "Hugo (World) (Aftermarket) (Unl)" + description "Hugo (World) (Aftermarket) (Unl)" + rom ( name "Hugo (World) (Aftermarket) (Unl).gbc" size 524288 crc 6581c78a sha1 390d2665f34ceaa5e34cc9f8f7c26d9e7583a92b ) ) game ( @@ -37116,6 +39489,12 @@ game ( rom ( name "Hyper Olympic Series - Track & Field GB (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 77f76ebc sha1 6dabafe260b53e61a810cbae2f14287adafffd8e ) ) +game ( + name "Ice Age II (Taiwan) (En) (Unl)" + description "Ice Age II (Taiwan) (En) (Unl)" + rom ( name "Ice Age II (Taiwan) (En) (Unl).gbc" size 2097152 crc 50bc8e9d sha1 c57912e67c135c48233f351f68cdc34020de8d01 ) +) + game ( name "Ide Yousuke no Mahjong Kyoushitsu GB (Japan)" description "Ide Yousuke no Mahjong Kyoushitsu GB (Japan)" @@ -37128,12 +39507,24 @@ game ( rom ( name "Indiana Jones and the Infernal Machine (USA, Europe) (En,Fr,De).gbc" size 1048576 crc 7fff1142 sha1 6d568438aa3b9b67c55aded582cec136b15c46d7 flags verified ) ) +game ( + name "Infall (World) (Aftermarket) (Unl)" + description "Infall (World) (Aftermarket) (Unl)" + rom ( name "Infall (World) (Aftermarket) (Unl).gbc" size 131072 crc d9d90319 sha1 aafaf33fa43c7f0fd65cc8af03a42df25361fc74 ) +) + game ( name "Infinity (USA) (Proto) (2001-03-22)" description "Infinity (USA) (Proto) (2001-03-22)" rom ( name "Infinity (USA) (Proto) (2001-03-22).gbc" size 2097152 crc 4ade94aa sha1 fdfd6d4cbebbf64fc7d1264f0450be270be89823 ) ) +game ( + name "Inspector Gadget - Operation Madkactus (Europe) (Fr) (Beta)" + description "Inspector Gadget - Operation Madkactus (Europe) (Fr) (Beta)" + rom ( name "Inspector Gadget - Operation Madkactus (Europe) (Fr) (Beta).gbc" size 1048576 crc 93ec798b sha1 8444ff17aa3f865eec33cc49398b450e345376c3 ) +) + game ( name "Inspector Gadget - Operation Madkactus (Europe) (En,Fr,De,Es,It,Nl)" description "Inspector Gadget - Operation Madkactus (Europe) (En,Fr,De,Es,It,Nl)" @@ -37146,6 +39537,12 @@ game ( rom ( name "Inspector Gadget - Operation Madkactus (USA).gbc" size 1048576 crc 1af0b489 sha1 b0fa81a35e605948df3b7f1fcb5893bab99d9d6a ) ) +game ( + name "Inspector Waffles Early Days (World) (v1.0.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Inspector Waffles Early Days (World) (v1.0.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Inspector Waffles Early Days (World) (v1.0.1) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc fea1cdb9 sha1 ac10ca63f15ca78af9f7d0eabb85eef8733aef50 ) +) + game ( name "International Karate 2000 (Europe)" description "International Karate 2000 (Europe)" @@ -37200,6 +39597,12 @@ game ( rom ( name "International Track & Field - Summer Games (Europe).gbc" size 1048576 crc d826c75f sha1 53e158cb23fa79026345dae775d9f020218f8bb2 ) ) +game ( + name "Iron Cor - Stainless (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + description "Iron Cor - Stainless (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Iron Cor - Stainless (World) (v2.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc d6c1c1ac sha1 d722e95155455cf146a97222ccbc2237bea86509 ) +) + game ( name "It's a World Rally (Japan) (SGB Enhanced) (GB Compatible)" description "It's a World Rally (Japan) (SGB Enhanced) (GB Compatible)" @@ -37266,6 +39669,12 @@ game ( rom ( name "Jay und die Spielzeugdiebe (Germany).gbc" size 1048576 crc 73f4f6da sha1 dd01d68bab2d3615f173e4c9c94da56248fab580 ) ) +game ( + name "Jayro's Game Boy Test Cartridge (World) (v1.18) (GB Compatible) (Aftermarket) (Unl)" + description "Jayro's Game Boy Test Cartridge (World) (v1.18) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Jayro's Game Boy Test Cartridge (World) (v1.18) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 9e97ac30 sha1 c07237d0f9c13b36ac2fcc5324b6e81122b0e189 ) +) + game ( name "Jeff Gordon XS Racing (USA) (GB Compatible)" description "Jeff Gordon XS Racing (USA) (GB Compatible)" @@ -37279,9 +39688,9 @@ game ( ) game ( - name "Jeremy McGrath Supercross 2000 (Japan) (En) (NP)" - description "Jeremy McGrath Supercross 2000 (Japan) (En) (NP)" - rom ( name "Jeremy McGrath Supercross 2000 (Japan) (En) (NP).gbc" size 1048576 crc 666d2a75 sha1 dd204c1d47290f52ef264ce32d59cb5f58a2701d ) + name "Jeremy McGrath Supercross 2000 (Japan) (En) (Possible Proto) (NP)" + description "Jeremy McGrath Supercross 2000 (Japan) (En) (Possible Proto) (NP)" + rom ( name "Jeremy McGrath Supercross 2000 (Japan) (En) (Possible Proto) (NP).gbc" size 1048576 crc 666d2a75 sha1 dd204c1d47290f52ef264ce32d59cb5f58a2701d ) ) game ( @@ -37290,6 +39699,12 @@ game ( rom ( name "Jet de Go! - Let's Go by Airliner (Japan).gbc" size 2097152 crc 20c4ccf6 sha1 97bf75afa0089ddb342ea7046b7cd113ba2c6fec ) ) +game ( + name "Jet Set Willy (World) (Aftermarket) (Unl)" + description "Jet Set Willy (World) (Aftermarket) (Unl)" + rom ( name "Jet Set Willy (World) (Aftermarket) (Unl).gbc" size 262144 crc 659295ee sha1 bcb5a0e4566572aeb6cddea0897903ba207dc54f ) +) + game ( name "Jibaku-kun - Rei no Itsuki no Kajitsu (Japan) (Proto)" description "Jibaku-kun - Rei no Itsuki no Kajitsu (Japan) (Proto)" @@ -37345,9 +39760,9 @@ game ( ) game ( - name "Jing Ling Wang III (Taiwan) (Unl)" - description "Jing Ling Wang III (Taiwan) (Unl)" - rom ( name "Jing Ling Wang III (Taiwan) (Unl).gbc" size 2097152 crc f19e780c sha1 8ef6ceb1b7894f43caa5f422d62d6c437f81e56d ) + name "Jingling Wang III (Taiwan) (Unl)" + description "Jingling Wang III (Taiwan) (Unl)" + rom ( name "Jingling Wang III (Taiwan) (Unl).gbc" size 2097152 crc f19e780c sha1 8ef6ceb1b7894f43caa5f422d62d6c437f81e56d ) ) game ( @@ -37369,9 +39784,9 @@ game ( ) game ( - name "Jissen ni Yakudatsu Tsumego (Japan)" - description "Jissen ni Yakudatsu Tsumego (Japan)" - rom ( name "Jissen ni Yakudatsu Tsumego (Japan).gbc" size 262144 crc 69c6dbef sha1 f7ed6cdce7637a11d7fa7f5cb59b8f8ce131f9d1 ) + name "Jissen ni Yakudatsu Tsumego (Japan) (Possible Proto)" + description "Jissen ni Yakudatsu Tsumego (Japan) (Possible Proto)" + rom ( name "Jissen ni Yakudatsu Tsumego (Japan) (Possible Proto).gbc" size 262144 crc 69c6dbef sha1 f7ed6cdce7637a11d7fa7f5cb59b8f8ce131f9d1 ) ) game ( @@ -37392,6 +39807,24 @@ game ( rom ( name "Joryuu Janshi ni Chousen GB - Watashi-tachi ni Chousen Shitene! (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 9fa5cdb5 sha1 a332817b9561dcab7d1f3dc0cf300e1656b253c3 ) ) +game ( + name "Judy's Adventure (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Judy's Adventure (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Judy's Adventure (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 8884d532 sha1 a41195443613fb4414d8536b1f3494677f6f253d ) +) + +game ( + name "Judy's Adventure (World) (v11.3) (GB Compatible) (Aftermarket) (Unl)" + description "Judy's Adventure (World) (v11.3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Judy's Adventure (World) (v11.3) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 570a8043 sha1 1ccbf555412a417135acea0b7b185a7f795a89da ) +) + +game ( + name "Juedui Wuli (Taiwan) (Unl)" + description "Juedui Wuli (Taiwan) (Unl)" + rom ( name "Juedui Wuli (Taiwan) (Unl).gbc" size 2097152 crc f4d63a7e sha1 f0b9f02335ee89aa6189e687e6e759d8c49bc2b3 ) +) + game ( name "JumpStart Dino Adventure - Field Trip (USA)" description "JumpStart Dino Adventure - Field Trip (USA)" @@ -37527,7 +39960,13 @@ game ( game ( name "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced) (GB Compatible)" description "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc bf80c897 sha1 857fb62dc310268e0b92e9383c6b6fd61aa33fa0 ) + rom ( name "Kaseki Sousei Reborn II - Monster Digger (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc bf80c897 sha1 857fb62dc310268e0b92e9383c6b6fd61aa33fa0 flags verified ) +) + +game ( + name "Katakis 3D (Europe) (Proto)" + description "Katakis 3D (Europe) (Proto)" + rom ( name "Katakis 3D (Europe) (Proto).gbc" size 2097152 crc 7c4b3795 sha1 8cd4be6772c592bbc2908fa826c090ec122e384c ) ) game ( @@ -37543,9 +39982,9 @@ game ( ) game ( - name "Kawa no Nushi Tsuri 4 (Japan) (Rev 1) (Rumble Version) (SGB Enhanced, GB Compatible) (NP)" - description "Kawa no Nushi Tsuri 4 (Japan) (Rev 1) (Rumble Version) (SGB Enhanced, GB Compatible) (NP)" - rom ( name "Kawa no Nushi Tsuri 4 (Japan) (Rev 1) (Rumble Version) (SGB Enhanced, GB Compatible) (NP).gbc" size 1048576 crc 456d4dfc sha1 69e56fd73eb365dba87713c2a3ea2e74bd63f63c ) + name "Kawa no Nushi Tsuri 4 (Japan) (Rev 1) (Possible Proto) (Rumble Version) (SGB Enhanced, GB Compatible) (NP)" + description "Kawa no Nushi Tsuri 4 (Japan) (Rev 1) (Possible Proto) (Rumble Version) (SGB Enhanced, GB Compatible) (NP)" + rom ( name "Kawa no Nushi Tsuri 4 (Japan) (Rev 1) (Possible Proto) (Rumble Version) (SGB Enhanced, GB Compatible) (NP).gbc" size 1048576 crc 456d4dfc sha1 69e56fd73eb365dba87713c2a3ea2e74bd63f63c ) ) game ( @@ -37602,6 +40041,12 @@ game ( rom ( name "Ken Griffey Jr.'s Slugfest (USA).gbc" size 1048576 crc 1e64d19c sha1 2362bdd8c26f30adb871259ce2d909ac6d505e36 ) ) +game ( + name "Kero Kero Cowboy (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Kero Kero Cowboy (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Kero Kero Cowboy (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 6a5abba1 sha1 0b3deef7a27201e81b4d39bc0bd10ff7ec73e380 ) +) + game ( name "Kettou Transformers Beast Wars - Beast Senshi Saikyou Ketteisen (Japan) (SGB Enhanced) (GB Compatible)" description "Kettou Transformers Beast Wars - Beast Senshi Saikyou Ketteisen (Japan) (SGB Enhanced) (GB Compatible)" @@ -37621,9 +40066,9 @@ game ( ) game ( - name "Kikstart (World) (Aftermarket) (Homebrew)" - description "Kikstart (World) (Aftermarket) (Homebrew)" - rom ( name "Kikstart (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 9a9f483b sha1 bc472506f73f0c1a3f0a610c0136b324b7635c7f ) + name "Kikstart (World) (Aftermarket) (Unl)" + description "Kikstart (World) (Aftermarket) (Unl)" + rom ( name "Kikstart (World) (Aftermarket) (Unl).gbc" size 524288 crc 9a9f483b sha1 bc472506f73f0c1a3f0a610c0136b324b7635c7f ) ) game ( @@ -37633,9 +40078,9 @@ game ( ) game ( - name "King Lion Advance III 2003 (USA) (Unl)" - description "King Lion Advance III 2003 (USA) (Unl)" - rom ( name "King Lion Advance III 2003 (USA) (Unl).gbc" size 2097152 crc 0c22466d sha1 7c43ccfca93cae23e04e58fa0d7d7400a9694e0e ) + name "King of Fighters R2 (Taiwan) (Unl)" + description "King of Fighters R2 (Taiwan) (Unl)" + rom ( name "King of Fighters R2 (Taiwan) (Unl).gbc" size 1048576 crc 9913e18b sha1 43c2b6f0c3559ed90032cba6569811047f9e20d0 ) ) game ( @@ -37723,9 +40168,9 @@ game ( ) game ( - name "Knit-Wit (World) (v1.1) (Aftermarket) (Homebrew)" - description "Knit-Wit (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Knit-Wit (World) (v1.1) (Aftermarket) (Homebrew).gbc" size 262144 crc f19d5e86 sha1 0f0e01a143182a9784c80a882ac206d02d8679d7 ) + name "Knit-Wit (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Knit-Wit (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Knit-Wit (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc f19d5e86 sha1 0f0e01a143182a9784c80a882ac206d02d8679d7 ) ) game ( @@ -37813,27 +40258,39 @@ game ( ) game ( - name "Kou Dai Guai Shou - Dong Zuo Pian (Taiwan) (En) (Unl)" - description "Kou Dai Guai Shou - Dong Zuo Pian (Taiwan) (En) (Unl)" - rom ( name "Kou Dai Guai Shou - Dong Zuo Pian (Taiwan) (En) (Unl).gbc" size 1048576 crc 14355371 sha1 f398086d1f8cb435a632e5ea45fb19e980b0568d ) + name "Koudai Guaishou - Dongzuo Pian (Taiwan) (En) (Unl)" + description "Koudai Guaishou - Dongzuo Pian (Taiwan) (En) (Unl)" + rom ( name "Koudai Guaishou - Dongzuo Pian (Taiwan) (En) (Unl).gbc" size 1048576 crc 14355371 sha1 f398086d1f8cb435a632e5ea45fb19e980b0568d ) ) game ( - name "Kou Dai Guai Shou - Dong Zuo Pian (Taiwan) (En) (Unl) (Alt)" - description "Kou Dai Guai Shou - Dong Zuo Pian (Taiwan) (En) (Unl) (Alt)" - rom ( name "Kou Dai Guai Shou - Dong Zuo Pian (Taiwan) (En) (Unl) (Alt).gbc" size 1048576 crc ec2fbdfd sha1 c7a1020797b57d292e16c5297199d977e025256b ) + name "Koudai Guaishou - Dongzuo Pian (Taiwan) (En) (Unl) (Alt)" + description "Koudai Guaishou - Dongzuo Pian (Taiwan) (En) (Unl) (Alt)" + rom ( name "Koudai Guaishou - Dongzuo Pian (Taiwan) (En) (Unl) (Alt).gbc" size 1048576 crc ec2fbdfd sha1 c7a1020797b57d292e16c5297199d977e025256b ) ) game ( - name "Kou Dai Guai Shou - Lan Bao Shi 2003 (Taiwan) (Unl)" - description "Kou Dai Guai Shou - Lan Bao Shi 2003 (Taiwan) (Unl)" - rom ( name "Kou Dai Guai Shou - Lan Bao Shi 2003 (Taiwan) (Unl).gbc" size 2097152 crc 4c76d4d8 sha1 d688201e6031b88f122ec753a37daedfb233b48d ) + name "Koudai Guaishou - Feicui Ban (Taiwan) (Unl)" + description "Koudai Guaishou - Feicui Ban (Taiwan) (Unl)" + rom ( name "Koudai Guaishou - Feicui Ban (Taiwan) (Unl).gbc" size 2097152 crc 8494465f sha1 a3b2818c778fe6b5811841a9f28a1a06334216ea ) ) game ( - name "Kou Dai Yao Guai - Bai Jin Ban (Taiwan) (Unl)" - description "Kou Dai Yao Guai - Bai Jin Ban (Taiwan) (Unl)" - rom ( name "Kou Dai Yao Guai - Bai Jin Ban (Taiwan) (Unl).gbc" size 2097152 crc 998ad382 sha1 f9013985d7c40eccfa863e2ba808e64deaa4b384 ) + name "Koudai Guaishou - Sheng Bianshi (China) (Unl)" + description "Koudai Guaishou - Sheng Bianshi (China) (Unl)" + rom ( name "Koudai Guaishou - Sheng Bianshi (China) (Unl).gbc" size 2097152 crc 0791c3a7 sha1 8a61c2dc4d1acf96d8ae871b0f371c7f8a17e9f1 ) +) + +game ( + name "Koudai Yaoguai - Baijin Ban (Taiwan) (Unl)" + description "Koudai Yaoguai - Baijin Ban (Taiwan) (Unl)" + rom ( name "Koudai Yaoguai - Baijin Ban (Taiwan) (Unl).gbc" size 2097152 crc 998ad382 sha1 f9013985d7c40eccfa863e2ba808e64deaa4b384 ) +) + +game ( + name "Koudai Yaoguai Lu Baoshi (Taiwan) (Unl)" + description "Koudai Yaoguai Lu Baoshi (Taiwan) (Unl)" + rom ( name "Koudai Yaoguai Lu Baoshi (Taiwan) (Unl).gbc" size 2097152 crc ee74e4a2 sha1 59e4550bd3958464188fd9b8c11b2dc1c9ad7d06 ) ) game ( @@ -37861,9 +40318,9 @@ game ( ) game ( - name "Lao Fuzi Chuanqi (Taiwan) (Unl)" - description "Lao Fuzi Chuanqi (Taiwan) (Unl)" - rom ( name "Lao Fuzi Chuanqi (Taiwan) (Unl).gbc" size 2097152 crc aeca45be sha1 b7193fcb8b9b8958a2522be0d1a3874cffc1e1db ) + name "Laofuzi Chuanqi (Taiwan) (Unl)" + description "Laofuzi Chuanqi (Taiwan) (Unl)" + rom ( name "Laofuzi Chuanqi (Taiwan) (Unl).gbc" size 2097152 crc aeca45be sha1 b7193fcb8b9b8958a2522be0d1a3874cffc1e1db ) ) game ( @@ -37873,21 +40330,27 @@ game ( ) game ( - name "Laser Squad (World) (Aftermarket) (Homebrew)" - description "Laser Squad (World) (Aftermarket) (Homebrew)" - rom ( name "Laser Squad (World) (Aftermarket) (Homebrew).gbc" size 1048576 crc 32f24248 sha1 26f4efe636214e72ec724f8887ca79fbc8abad80 ) + name "Laser Squad Alter (World) (Aftermarket) (Unl)" + description "Laser Squad Alter (World) (Aftermarket) (Unl)" + rom ( name "Laser Squad Alter (World) (Aftermarket) (Unl).gbc" size 1048576 crc 32f24248 sha1 26f4efe636214e72ec724f8887ca79fbc8abad80 ) ) game ( - name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Beta)" - description "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Beta)" - rom ( name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Beta).gbc" size 1048576 crc f90a3dae sha1 772539821e4b703259b2e2ad535d74a03fa22760 ) + name "Last Crown Warriors (World) (v1.0.1) (Demo) (Kickstarter) (GB Compatible) (Aftermarket) (Unl)" + description "Last Crown Warriors (World) (v1.0.1) (Demo) (Kickstarter) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Last Crown Warriors (World) (v1.0.1) (Demo) (Kickstarter) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 4a58315b sha1 5a234e33f7429b48f4374b5989e6df4d20352b4c ) ) game ( - name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Rev 1) (Proto)" - description "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Rev 1) (Proto)" - rom ( name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Rev 1) (Proto).gbc" size 1048576 crc cf8e2371 sha1 f7b19c1501d325dd8ee219ccae2eaca130a5a21b ) + name "Last Crown Warriors (World) (v2.1.0) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Last Crown Warriors (World) (v2.1.0) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Last Crown Warriors (World) (v2.1.0) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 5c405584 sha1 3ee043ba17f46a6afbbba8ac05f35d093b817fbc ) +) + +game ( + name "Last Crown Warriors (World) (v2.1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Last Crown Warriors (World) (v2.1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Last Crown Warriors (World) (v2.1.1) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 9a134100 sha1 75b5188a5b8a720ff08894379147c7870ac8825d ) ) game ( @@ -37902,12 +40365,42 @@ game ( rom ( name "Laura (USA).gbc" size 1048576 crc e2bff286 sha1 3fe3eb99ee818c94e9a07e19640af6a2aad33903 ) ) +game ( + name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Beta)" + description "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Beta)" + rom ( name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Beta).gbc" size 1048576 crc f90a3dae sha1 772539821e4b703259b2e2ad535d74a03fa22760 ) +) + +game ( + name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Rev 1) (Proto)" + description "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Rev 1) (Proto)" + rom ( name "Laura (Europe) (En,Fr,De,Es,It,Nl,Sv,Da) (Rev 1) (Proto).gbc" size 1048576 crc cf8e2371 sha1 f7b19c1501d325dd8ee219ccae2eaca130a5a21b ) +) + game ( name "Le Mans 24 Hours (Europe) (En,Fr,De,Es,It)" description "Le Mans 24 Hours (Europe) (En,Fr,De,Es,It)" rom ( name "Le Mans 24 Hours (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 1b49d07d sha1 cb4847cd63c8cc52f04bf4d86d54954be3d8fc1a ) ) +game ( + name "Leaper (World) (Aftermarket) (Unl)" + description "Leaper (World) (Aftermarket) (Unl)" + rom ( name "Leaper (World) (Aftermarket) (Unl).gbc" size 524288 crc ed8cd385 sha1 425db2916263121f4aee91a8cab6286e39364f87 ) +) + +game ( + name "Legacy of Verintia (World) (2023-05-15) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Legacy of Verintia (World) (2023-05-15) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Legacy of Verintia (World) (2023-05-15) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 953e25d1 sha1 018c7cada41e693a02b9c596d307b0aa9207eef4 ) +) + +game ( + name "Legacy of Verintia (World) (2023-05-31) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Legacy of Verintia (World) (2023-05-31) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Legacy of Verintia (World) (2023-05-31) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 1096252a sha1 c22cc79b25a05afad66e769dc0365b7c25f1bb85 ) +) + game ( name "Legend of the River King 2 (Europe) (SGB Enhanced) (GB Compatible)" description "Legend of the River King 2 (Europe) (SGB Enhanced) (GB Compatible)" @@ -37980,6 +40473,24 @@ game ( rom ( name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev 2) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 06887a34 sha1 1c091225688d966928cc74336dbef2e07d12a47c flags verified ) ) +game ( + name "Legend of Zelda, The - Link's Awakening DX (France) (Beta) (1998-12-11) (SGB Enhanced) (GB Compatible)" + description "Legend of Zelda, The - Link's Awakening DX (France) (Beta) (1998-12-11) (SGB Enhanced) (GB Compatible)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (France) (Beta) (1998-12-11) (SGB Enhanced) (GB Compatible).gbc" size 1015808 crc c17259db sha1 a5a6f0251e8eafd0a02b1eeceaa5b51705c12f0d ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (France) (Beta) (1999-09-22) (SGB Enhanced) (GB Compatible)" + description "Legend of Zelda, The - Link's Awakening DX (France) (Beta) (1999-09-22) (SGB Enhanced) (GB Compatible)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (France) (Beta) (1999-09-22) (SGB Enhanced) (GB Compatible).gbc" size 1015808 crc 8afd751e sha1 797925a26eb39656aea60e10c8e9dd986b515b53 ) +) + +game ( + name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev 2) (Beta) (1999-09-23) (SGB Enhanced) (GB Compatible)" + description "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev 2) (Beta) (1999-09-23) (SGB Enhanced) (GB Compatible)" + rom ( name "Legend of Zelda, The - Link's Awakening DX (USA, Europe) (Rev 2) (Beta) (1999-09-23) (SGB Enhanced) (GB Compatible).gbc" size 1015808 crc 0559bc89 sha1 dbe7a909c71d407f01af2cdb0aaf7d164ac7a9bd ) +) + game ( name "Legend of Zelda, The - Link's Awakening DX (Germany) (Beta) (1998-12-11) (SGB Enhanced) (GB Compatible)" description "Legend of Zelda, The - Link's Awakening DX (Germany) (Beta) (1998-12-11) (SGB Enhanced) (GB Compatible)" @@ -38131,9 +40642,21 @@ game ( ) game ( - name "Liberator (World) (Aftermarket) (Homebrew)" - description "Liberator (World) (Aftermarket) (Homebrew)" - rom ( name "Liberator (World) (Aftermarket) (Homebrew).gbc" size 262144 crc ebe70d3d sha1 e3afce5a2357732ed15d7f3c0900f7b48113efdc ) + name "Let's Bee Friends (World) (GB Compatible) (Aftermarket) (Unl)" + description "Let's Bee Friends (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Let's Bee Friends (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc a91a698f sha1 26f38b3908c086b3e349324da32bc37213975030 ) +) + +game ( + name "Liberator (World) (Aftermarket) (Unl)" + description "Liberator (World) (Aftermarket) (Unl)" + rom ( name "Liberator (World) (Aftermarket) (Unl).gbc" size 262144 crc ebe70d3d sha1 e3afce5a2357732ed15d7f3c0900f7b48113efdc ) +) + +game ( + name "Lightseeker (World) (GB Compatible) (Aftermarket) (Unl)" + description "Lightseeker (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Lightseeker (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc b8dd8409 sha1 281abb583ec0039e2c981c2e95f7a92002da081b ) ) game ( @@ -38163,7 +40686,7 @@ game ( game ( name "Little Mermaid II, The - Pinball Frenzy (USA) (En,Fr,De,Es,It) (Rumble Version)" description "Little Mermaid II, The - Pinball Frenzy (USA) (En,Fr,De,Es,It) (Rumble Version)" - rom ( name "Little Mermaid II, The - Pinball Frenzy (USA) (En,Fr,De,Es,It) (Rumble Version).gbc" size 1048576 crc 364f9ccd sha1 0940a1a86127cf8228a6a015035d8189218f57db ) + rom ( name "Little Mermaid II, The - Pinball Frenzy (USA) (En,Fr,De,Es,It) (Rumble Version).gbc" size 1048576 crc 364f9ccd sha1 0940a1a86127cf8228a6a015035d8189218f57db flags verified ) ) game ( @@ -38184,6 +40707,12 @@ game ( rom ( name "LNF Stars 2001 (France).gbc" size 1048576 crc f8bf3ee7 sha1 07a0e1c0ddde6371dbaf25fd016bdc77c0eca090 ) ) +game ( + name "Loco-coco (World) (Aftermarket) (Unl)" + description "Loco-coco (World) (Aftermarket) (Unl)" + rom ( name "Loco-coco (World) (Aftermarket) (Unl).gbc" size 262144 crc f6b9fe4e sha1 8a8972ff3e208280a746a2015a20f67248180a1c ) +) + game ( name "Lode Runner - Domudomu Dan no Yabou (Japan) (GB Compatible)" description "Lode Runner - Domudomu Dan no Yabou (Japan) (GB Compatible)" @@ -38385,7 +40914,7 @@ game ( game ( name "Lucky Luke (Europe) (En,Fr,De,Es)" description "Lucky Luke (Europe) (En,Fr,De,Es)" - rom ( name "Lucky Luke (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 412fb57c sha1 36b59251751a55285dbedc3bd4b33b2c73b811c9 ) + rom ( name "Lucky Luke (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 412fb57c sha1 36b59251751a55285dbedc3bd4b33b2c73b811c9 flags verified ) ) game ( @@ -38431,15 +40960,21 @@ game ( ) game ( - name "Lunar Docking (World) (Aftermarket) (Homebrew)" - description "Lunar Docking (World) (Aftermarket) (Homebrew)" - rom ( name "Lunar Docking (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 9edd066c sha1 4d43a38e8b5df41309f5b6ec13e4829db739d980 ) + name "Lunar Docking (World) (2021-12-30) (Aftermarket) (Unl)" + description "Lunar Docking (World) (2021-12-30) (Aftermarket) (Unl)" + rom ( name "Lunar Docking (World) (2021-12-30) (Aftermarket) (Unl).gbc" size 262144 crc 9edd066c sha1 4d43a38e8b5df41309f5b6ec13e4829db739d980 ) ) game ( - name "Luo Ke Ying Xiong EXE5 (Taiwan) (Unl)" - description "Luo Ke Ying Xiong EXE5 (Taiwan) (Unl)" - rom ( name "Luo Ke Ying Xiong EXE5 (Taiwan) (Unl).gbc" size 2097152 crc 51f92403 sha1 c498a5fb261e921828831bff5c2c705453ea314e ) + name "Lunar Docking (World) (2022-08-07) (Aftermarket) (Unl)" + description "Lunar Docking (World) (2022-08-07) (Aftermarket) (Unl)" + rom ( name "Lunar Docking (World) (2022-08-07) (Aftermarket) (Unl).gbc" size 262144 crc de5d5c0b sha1 5f038ef3657d3fbfb3be6917b24c3f933363ad4c ) +) + +game ( + name "Luoke Yingxiong EXE5 (Taiwan) (Unl)" + description "Luoke Yingxiong EXE5 (Taiwan) (Unl)" + rom ( name "Luoke Yingxiong EXE5 (Taiwan) (Unl).gbc" size 2097152 crc 51f92403 sha1 c498a5fb261e921828831bff5c2c705453ea314e ) ) game ( @@ -38467,15 +41002,15 @@ game ( ) game ( - name "Machine, The (USA) (v1.1) (Demo) (Aftermarket) (Homebrew)" - description "Machine, The (USA) (v1.1) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Machine, The (USA) (v1.1) (Demo) (Aftermarket) (Homebrew).gbc" size 2097152 crc f55a9d95 sha1 2b22fbd76e11e6e45053b1e6989de303e3033c9e ) + name "Machine, The (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Machine, The (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Machine, The (World) (v1.1) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc f55a9d95 sha1 2b22fbd76e11e6e45053b1e6989de303e3033c9e ) ) game ( - name "Machine, The (USA) (Demo) (Aftermarket) (Homebrew)" - description "Machine, The (USA) (Demo) (Aftermarket) (Homebrew)" - rom ( name "Machine, The (USA) (Demo) (Aftermarket) (Homebrew).gbc" size 2097152 crc 5662865e sha1 a5ac99a4087bd5ea45417e5b4a7c9af10433911a ) + name "Machine, The (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Machine, The (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Machine, The (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 5662865e sha1 a5ac99a4087bd5ea45417e5b4a7c9af10433911a ) ) game ( @@ -38490,6 +41025,12 @@ game ( rom ( name "Madden NFL 2000 (USA, Europe) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 482944aa sha1 df03f3e5e3f6fd3905dc332b307b5566f0f35252 flags verified ) ) +game ( + name "Madden NFL 2000 (USA, Europe) (Beta) (SGB Enhanced) (GB Compatible)" + description "Madden NFL 2000 (USA, Europe) (Beta) (SGB Enhanced) (GB Compatible)" + rom ( name "Madden NFL 2000 (USA, Europe) (Beta) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc b3fead85 sha1 09bf3dea1dc01b018ba86e3affbcbab7b9d2eb63 ) +) + game ( name "Madden NFL 2001 (USA)" description "Madden NFL 2001 (USA)" @@ -38514,6 +41055,12 @@ game ( rom ( name "Magi-Nation - Keeper's Quest (USA) (Proto).gbc" size 1048576 crc 89de57b7 sha1 7c6b427810be2f0d7496ccb5eff2226d3ed1194e ) ) +game ( + name "Magic & Legend - Time Knights (World) (Demo) (The Retro Room) (GB Compatible) (Aftermarket) (Unl)" + description "Magic & Legend - Time Knights (World) (Demo) (The Retro Room) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Magic & Legend - Time Knights (World) (Demo) (The Retro Room) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc c276843d sha1 852697a2952d2e7375b73aba877ebc17aa4f4179 ) +) + game ( name "Magical Chase GB - Minarai Mahoutsukai Kenja no Tani e (Japan)" description "Magical Chase GB - Minarai Mahoutsukai Kenja no Tani e (Japan)" @@ -38532,6 +41079,12 @@ game ( rom ( name "Magical Drop (USA).gbc" size 1048576 crc e4188a79 sha1 2106b22776a87825d3edb408503e719f4927c3e6 ) ) +game ( + name "Magical Drop (Europe) (En,Fr,De) (Beta)" + description "Magical Drop (Europe) (En,Fr,De) (Beta)" + rom ( name "Magical Drop (Europe) (En,Fr,De) (Beta).gbc" size 1048576 crc 799e2020 sha1 99fbf24ca924acf5a4ea64817fb29d6e408cb722 ) +) + game ( name "Magical Tetris Challenge (Europe) (En,Fr,De,Es,It,Nl,Sv)" description "Magical Tetris Challenge (Europe) (En,Fr,De,Es,It,Nl,Sv)" @@ -38551,9 +41104,9 @@ game ( ) game ( - name "Magician's Curse, The (World) (Aftermarket) (Homebrew)" - description "Magician's Curse, The (World) (Aftermarket) (Homebrew)" - rom ( name "Magician's Curse, The (World) (Aftermarket) (Homebrew).gbc" size 524288 crc f2b1967e sha1 3b5f97f9a0b4d63a3795695b0bda6e969de8e051 ) + name "Magician's Curse, The (World) (Aftermarket) (Unl)" + description "Magician's Curse, The (World) (Aftermarket) (Unl)" + rom ( name "Magician's Curse, The (World) (Aftermarket) (Unl).gbc" size 524288 crc f2b1967e sha1 3b5f97f9a0b4d63a3795695b0bda6e969de8e051 ) ) game ( @@ -38736,6 +41289,12 @@ game ( rom ( name "Maya the Bee & Her Friends (Europe) (En,Fr,De) (GB Compatible).gbc" size 1048576 crc 983b1d26 sha1 522d7f33fd39bd00f48208743fb2246ef0bd3ff1 ) ) +game ( + name "Mayhem (World) (Aftermarket) (Unl)" + description "Mayhem (World) (Aftermarket) (Unl)" + rom ( name "Mayhem (World) (Aftermarket) (Unl).gbc" size 262144 crc 4d739ad7 sha1 9f141728a74432820f47cc24d230dc56d6ac099b ) +) + game ( name "McDonald's Monogatari - Honobono Tenchou Ikusei Game (Japan)" description "McDonald's Monogatari - Honobono Tenchou Ikusei Game (Japan)" @@ -38751,7 +41310,7 @@ game ( game ( name "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced) (GB Compatible)" description "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 5b8ffd37 sha1 48fc8c6e84c63ee47f5a2c5e99dc1666d6e9f496 ) + rom ( name "Medarot 2 - Kuwagata Version (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 5b8ffd37 sha1 48fc8c6e84c63ee47f5a2c5e99dc1666d6e9f496 flags verified ) ) game ( @@ -38817,7 +41376,7 @@ game ( game ( name "Mega Man Xtreme (USA, Europe) (GB Compatible)" description "Mega Man Xtreme (USA, Europe) (GB Compatible)" - rom ( name "Mega Man Xtreme (USA, Europe) (GB Compatible).gbc" size 1048576 crc 3a4d94d5 sha1 c877449ba0889fdcacf23c49b0611d0ca57283c5 ) + rom ( name "Mega Man Xtreme (USA, Europe) (GB Compatible).gbc" size 1048576 crc 3a4d94d5 sha1 c877449ba0889fdcacf23c49b0611d0ca57283c5 flags verified ) ) game ( @@ -38869,9 +41428,21 @@ game ( ) game ( - name "Memory Mania Challenge (World) (v1.3) (Aftermarket) (Homebrew)" - description "Memory Mania Challenge (World) (v1.3) (Aftermarket) (Homebrew)" - rom ( name "Memory Mania Challenge (World) (v1.3) (Aftermarket) (Homebrew).gbc" size 1048576 crc 50618f4b sha1 c8d74af4746313800df3a23c1ad01f931e0e2eca flags verified ) + name "Melanie and the Magic Forest (World) (GB Compatible) (Aftermarket) (Unl)" + description "Melanie and the Magic Forest (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Melanie and the Magic Forest (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc f614bdff sha1 7e46c193f6566f620acf20ead3a1fca1d677c221 ) +) + +game ( + name "Melanie and the Magic Forest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Melanie and the Magic Forest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Melanie and the Magic Forest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 949c6ab9 sha1 34269af4db6c37b92fdc7f7f914c282174603ba8 ) +) + +game ( + name "Memory Mania Challenge (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + description "Memory Mania Challenge (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Memory Mania Challenge (World) (v1.3) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 50618f4b sha1 c8d74af4746313800df3a23c1ad01f931e0e2eca flags verified ) ) game ( @@ -38940,6 +41511,12 @@ game ( rom ( name "Metamode (Japan).gbc" size 2097152 crc a76eed5b sha1 1c1d74c810b90cf4d2ee32859eaea569a5b45c3f ) ) +game ( + name "Meteorite (World) (Aftermarket) (Unl)" + description "Meteorite (World) (Aftermarket) (Unl)" + rom ( name "Meteorite (World) (Aftermarket) (Unl).gbc" size 131072 crc fafbcebf sha1 25a81d916f1ed80a2bca2fe7a555433f06d025e3 ) +) + game ( name "Mia Hamm Soccer Shootout (USA)" description "Mia Hamm Soccer Shootout (USA)" @@ -38964,6 +41541,12 @@ game ( rom ( name "Micro Machines 1 and 2 - Twin Turbo (USA, Europe).gbc" size 2097152 crc 5dd337eb sha1 18b5c14ee3b3f3c16b9d641c3b3824b15c0a0c78 ) ) +game ( + name "Micro Machines 2 - Turbo Tournament (Europe) (Proto)" + description "Micro Machines 2 - Turbo Tournament (Europe) (Proto)" + rom ( name "Micro Machines 2 - Turbo Tournament (Europe) (Proto).gbc" size 2097152 crc e932c818 sha1 cbdefc7f63bf9a6c0fc15d7ab72b4b532b0d2422 ) +) + game ( name "Micro Machines V3 (USA, Europe)" description "Micro Machines V3 (USA, Europe)" @@ -39012,6 +41595,18 @@ game ( rom ( name "Microsoft Pinball Arcade (Europe).gbc" size 1048576 crc 4eb7db14 sha1 f2874f0f3023d96edbdb94e5c0dc181d8baa3efb flags verified ) ) +game ( + name "Midterm Moments (World) (2022-05-28) (GB Compatible) (Aftermarket) (Unl)" + description "Midterm Moments (World) (2022-05-28) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Midterm Moments (World) (2022-05-28) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc f9a5ed4e sha1 8b3e18287d5adf3b5a711e28a896f843927f22a2 ) +) + +game ( + name "Midterm Moments (World) (2022-06-15) (GB Compatible) (Aftermarket) (Unl)" + description "Midterm Moments (World) (2022-06-15) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Midterm Moments (World) (2022-06-15) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 177f0b6e sha1 e5fdb741d870de25affdc841c07eaa3000da25f5 ) +) + game ( name "Midway Presents Arcade Hits - Joust & Defender (USA, Europe) (GB Compatible)" description "Midway Presents Arcade Hits - Joust & Defender (USA, Europe) (GB Compatible)" @@ -39061,9 +41656,9 @@ game ( ) game ( - name "Mirror Between Us, The (World) (Aftermarket) (Homebrew)" - description "Mirror Between Us, The (World) (Aftermarket) (Homebrew)" - rom ( name "Mirror Between Us, The (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 854f4297 sha1 a1a44ce8052f06349df3cbdf9a6d976609213d68 ) + name "Mirror Between Us, The (World) (GB Compatible) (Aftermarket) (Unl)" + description "Mirror Between Us, The (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Mirror Between Us, The (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 854f4297 sha1 a1a44ce8052f06349df3cbdf9a6d976609213d68 ) ) game ( @@ -39091,9 +41686,9 @@ game ( ) game ( - name "Mission - Impossible (Europe) (En,Fr,De,Es,It) (Rev 1)" - description "Mission - Impossible (Europe) (En,Fr,De,Es,It) (Rev 1)" - rom ( name "Mission - Impossible (Europe) (En,Fr,De,Es,It) (Rev 1).gbc" size 1048576 crc 9c51f4c7 sha1 f822bda01d881f34d1e17664465faf6a3ff64356 ) + name "Mission - Impossible (Europe) (En,Fr,De,Es,It) (Rev 1) (Possible Proto)" + description "Mission - Impossible (Europe) (En,Fr,De,Es,It) (Rev 1) (Possible Proto)" + rom ( name "Mission - Impossible (Europe) (En,Fr,De,Es,It) (Rev 1) (Possible Proto).gbc" size 1048576 crc 9c51f4c7 sha1 f822bda01d881f34d1e17664465faf6a3ff64356 ) ) game ( @@ -39103,9 +41698,9 @@ game ( ) game ( - name "Mission to Mars (World) (Aftermarket) (Homebrew)" - description "Mission to Mars (World) (Aftermarket) (Homebrew)" - rom ( name "Mission to Mars (World) (Aftermarket) (Homebrew).gbc" size 262144 crc f651fcf4 sha1 479c70dd9c63cdcad99ca44720a9e0e2582df119 ) + name "Mission Mars (World) (Aftermarket) (Unl)" + description "Mission Mars (World) (Aftermarket) (Unl)" + rom ( name "Mission Mars (World) (Aftermarket) (Unl).gbc" size 262144 crc f651fcf4 sha1 479c70dd9c63cdcad99ca44720a9e0e2582df119 ) ) game ( @@ -39114,24 +41709,6 @@ game ( rom ( name "Mizuki Shigeru no Shin Youkaiden (Japan).gbc" size 4194304 crc fc1f100f sha1 ab12770558fb95434bba0da0d3b8a91e2d9179fb ) ) -game ( - name "Mo Jie 3 - Bu Wanme De Shijie (Taiwan) (Unl)" - description "Mo Jie 3 - Bu Wanme De Shijie (Taiwan) (Unl)" - rom ( name "Mo Jie 3 - Bu Wanme De Shijie (Taiwan) (Unl).gbc" size 524288 crc d91e3f98 sha1 556913f2687a49034e1229ef1e375f6036ec5719 ) -) - -game ( - name "Mo Jie Chuan Shuo (Taiwan) (Unl)" - description "Mo Jie Chuan Shuo (Taiwan) (Unl)" - rom ( name "Mo Jie Chuan Shuo (Taiwan) (Unl).gbc" size 524288 crc 7aa7eea5 sha1 109e4ba61b04afe15cc5a5ee994f56405938cee3 ) -) - -game ( - name "Mo Shou Shi Ji - Zhan Shen (Taiwan) (Unl)" - description "Mo Shou Shi Ji - Zhan Shen (Taiwan) (Unl)" - rom ( name "Mo Shou Shi Ji - Zhan Shen (Taiwan) (Unl).gbc" size 2097152 crc 80c4fd52 sha1 d2569f8176164cef1cc2a8bd94949ea9cd7dbbea ) -) - game ( name "Mobile Golf (Japan)" description "Mobile Golf (Japan)" @@ -39145,15 +41722,39 @@ game ( ) game ( - name "Momotarou Densetsu 1-2 (Japan)" - description "Momotarou Densetsu 1-2 (Japan)" - rom ( name "Momotarou Densetsu 1-2 (Japan).gbc" size 2097152 crc da7fb08f sha1 acffa3417c85be574aa28432e29e1d40f28a565b ) + name "Mojie 3-bu Wanme de Shijie (Taiwan) (Zh) (Unl)" + description "Mojie 3-bu Wanme de Shijie (Taiwan) (Zh) (Unl)" + rom ( name "Mojie 3-bu Wanme de Shijie (Taiwan) (Zh) (Unl).gbc" size 524288 crc d91e3f98 sha1 556913f2687a49034e1229ef1e375f6036ec5719 ) ) game ( - name "Mona and the Witch's Hat Deluxe (World) (Aftermarket) (Homebrew)" - description "Mona and the Witch's Hat Deluxe (World) (Aftermarket) (Homebrew)" - rom ( name "Mona and the Witch's Hat Deluxe (World) (Aftermarket) (Homebrew).gbc" size 131072 crc 39480c79 sha1 4348a7903e538e5367f2a60718f43cbeeccf96df ) + name "Mojie Chuanshuo (Taiwan) (Unl)" + description "Mojie Chuanshuo (Taiwan) (Unl)" + rom ( name "Mojie Chuanshuo (Taiwan) (Unl).gbc" size 524288 crc 7aa7eea5 sha1 109e4ba61b04afe15cc5a5ee994f56405938cee3 ) +) + +game ( + name "Mojie Zhanshi Chuanshuo (Taiwan) (Unl)" + description "Mojie Zhanshi Chuanshuo (Taiwan) (Unl)" + rom ( name "Mojie Zhanshi Chuanshuo (Taiwan) (Unl).gbc" size 2097152 crc 620c56b8 sha1 25fd8c132601cd9f74784a010141572505a2ef66 ) +) + +game ( + name "Momotarou Densetsu 1-2 (Japan)" + description "Momotarou Densetsu 1-2 (Japan)" + rom ( name "Momotarou Densetsu 1-2 (Japan).gbc" size 2097152 crc da7fb08f sha1 acffa3417c85be574aa28432e29e1d40f28a565b flags verified ) +) + +game ( + name "Mona and the Witch's Hat Deluxe (World) (GB Compatible) (Aftermarket) (Unl)" + description "Mona and the Witch's Hat Deluxe (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Mona and the Witch's Hat Deluxe (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 39480c79 sha1 4348a7903e538e5367f2a60718f43cbeeccf96df ) +) + +game ( + name "Monkey Magic (World) (Aftermarket) (Unl)" + description "Monkey Magic (World) (Aftermarket) (Unl)" + rom ( name "Monkey Magic (World) (Aftermarket) (Unl).gbc" size 262144 crc c9c68715 sha1 bf5dc5593334fe1114461065a2b7284d28b31462 ) ) game ( @@ -39183,7 +41784,7 @@ game ( game ( name "Monster Farm Battle Card GB (Japan) (SGB Enhanced) (GB Compatible)" description "Monster Farm Battle Card GB (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Monster Farm Battle Card GB (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 69b88f1e sha1 7e036e175c9e865572ab613ae0f8e6d3642ffb0e ) + rom ( name "Monster Farm Battle Card GB (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 69b88f1e sha1 7e036e175c9e865572ab613ae0f8e6d3642ffb0e flags verified ) ) game ( @@ -39217,9 +41818,9 @@ game ( ) game ( - name "Monster Traveler (Japan)" - description "Monster Traveler (Japan)" - rom ( name "Monster Traveler (Japan).gbc" size 4194304 crc 5d596cf6 sha1 5195f55ad6aaa302c0a0e11c0ec6ecad4efe0e27 ) + name "Monster Traveler (Japan) (Possible Proto)" + description "Monster Traveler (Japan) (Possible Proto)" + rom ( name "Monster Traveler (Japan) (Possible Proto).gbc" size 4194304 crc 5d596cf6 sha1 5195f55ad6aaa302c0a0e11c0ec6ecad4efe0e27 ) ) game ( @@ -39259,9 +41860,9 @@ game ( ) game ( - name "Monty on the Run (World) (Aftermarket) (Homebrew)" - description "Monty on the Run (World) (Aftermarket) (Homebrew)" - rom ( name "Monty on the Run (World) (Aftermarket) (Homebrew).gbc" size 524288 crc fd1066ac sha1 8390175e6be4731d9afa91715d7f8dd11693bb69 ) + name "Monty on the Run (World) (Aftermarket) (Unl)" + description "Monty on the Run (World) (Aftermarket) (Unl)" + rom ( name "Monty on the Run (World) (Aftermarket) (Unl).gbc" size 524288 crc fd1066ac sha1 8390175e6be4731d9afa91715d7f8dd11693bb69 ) ) game ( @@ -39306,6 +41907,12 @@ game ( rom ( name "Mortal Kombat 4 (USA, Europe) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 4eb71448 sha1 ea54fb35cd8c4d4cea234423a81f8f953b1d33e4 ) ) +game ( + name "Moshou Shiji - Zhanshen (Taiwan) (Unl)" + description "Moshou Shiji - Zhanshen (Taiwan) (Unl)" + rom ( name "Moshou Shiji - Zhanshen (Taiwan) (Unl).gbc" size 2097152 crc 80c4fd52 sha1 d2569f8176164cef1cc2a8bd94949ea9cd7dbbea ) +) + game ( name "Motocross Maniacs 2 (USA)" description "Motocross Maniacs 2 (USA)" @@ -39313,9 +41920,15 @@ game ( ) game ( - name "Mr. Angry (World) (Aftermarket) (Homebrew)" - description "Mr. Angry (World) (Aftermarket) (Homebrew)" - rom ( name "Mr. Angry (World) (Aftermarket) (Homebrew).gbc" size 524288 crc b85e63a5 sha1 127ad5315e2bce37614a1e9f8605798e68718926 ) + name "Mountain Climber (World) (En,Es) (GB Compatible) (Aftermarket) (Unl)" + description "Mountain Climber (World) (En,Es) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Mountain Climber (World) (En,Es) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 362a84ba sha1 b4b3afa2379a07acab6965ae8fcf6d2ba82d6d7e ) +) + +game ( + name "Mr. Angry (World) (Aftermarket) (Unl)" + description "Mr. Angry (World) (Aftermarket) (Unl)" + rom ( name "Mr. Angry (World) (Aftermarket) (Unl).gbc" size 524288 crc b85e63a5 sha1 127ad5315e2bce37614a1e9f8605798e68718926 ) ) game ( @@ -39385,9 +41998,15 @@ game ( ) game ( - name "Mu Chang Wu Yu GB 6 (Taiwan) (Unl)" - description "Mu Chang Wu Yu GB 6 (Taiwan) (Unl)" - rom ( name "Mu Chang Wu Yu GB 6 (Taiwan) (Unl).gbc" size 2097152 crc 416e6efa sha1 86b2de0fc2806f3d13145e2c0296389ec0897a6a ) + name "Muchang Wuyu GB 6 (Taiwan) (Unl)" + description "Muchang Wuyu GB 6 (Taiwan) (Unl)" + rom ( name "Muchang Wuyu GB 6 (Taiwan) (Unl).gbc" size 2097152 crc 416e6efa sha1 86b2de0fc2806f3d13145e2c0296389ec0897a6a ) +) + +game ( + name "Mud Warriors (World) (GB Compatible) (Aftermarket) (Unl)" + description "Mud Warriors (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Mud Warriors (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 846afc79 sha1 dae84fbc60839da29878714cd845c3704b915323 ) ) game ( @@ -39414,12 +42033,36 @@ game ( rom ( name "Mummy, The (USA).gbc" size 1048576 crc c6ba9f27 sha1 35b10f392d514bce858c8c64f9c489500466d0ff ) ) +game ( + name "Musical Notes (World) (2023-05-27) (Aftermarket) (Unl)" + description "Musical Notes (World) (2023-05-27) (Aftermarket) (Unl)" + rom ( name "Musical Notes (World) (2023-05-27) (Aftermarket) (Unl).gbc" size 524288 crc ec4f9d49 sha1 357db81755f1f0eb732367dd4090c446eb226ddf ) +) + +game ( + name "Musical Notes (World) (2023-05-19) (Aftermarket) (Unl)" + description "Musical Notes (World) (2023-05-19) (Aftermarket) (Unl)" + rom ( name "Musical Notes (World) (2023-05-19) (Aftermarket) (Unl).gbc" size 524288 crc 1ba7d27f sha1 d4c4be65ba469369cd90aaa733d0a8e8af6bcdc1 ) +) + game ( name "Muteki Ou Tri-Zenon (Japan)" description "Muteki Ou Tri-Zenon (Japan)" rom ( name "Muteki Ou Tri-Zenon (Japan).gbc" size 2097152 crc 0bab7a61 sha1 2a7f422bf9af9aff126e47ede8b5ceec0630eb08 ) ) +game ( + name "My Friendly Little Island (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl)" + description "My Friendly Little Island (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "My Friendly Little Island (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 9bff7b15 sha1 1f3aac8a3725cd1d0968529afc1c2031372d8ed1 ) +) + +game ( + name "My Friendly Little Island (World) (Aftermarket) (Unl)" + description "My Friendly Little Island (World) (Aftermarket) (Unl)" + rom ( name "My Friendly Little Island (World) (Aftermarket) (Unl).gbc" size 1048576 crc f6bf0584 sha1 81d724ad696084283712145adfef15769648b045 ) +) + game ( name "Mythri (USA) (Proto 1) (2000-08-02)" description "Mythri (USA) (Proto 1) (2000-08-02)" @@ -39495,7 +42138,7 @@ game ( game ( name "Nakayoshi Pet Series 4 - Kawaii Koneko (Japan)" description "Nakayoshi Pet Series 4 - Kawaii Koneko (Japan)" - rom ( name "Nakayoshi Pet Series 4 - Kawaii Koneko (Japan).gbc" size 1048576 crc 1a382367 sha1 e5d5f1092e991a7538b9d24a12de35da21e23edd ) + rom ( name "Nakayoshi Pet Series 4 - Kawaii Koneko (Japan).gbc" size 1048576 crc 1a382367 sha1 e5d5f1092e991a7538b9d24a12de35da21e23edd flags verified ) ) game ( @@ -39559,9 +42202,9 @@ game ( ) game ( - name "NBA in the Zone (USA) (SGB Enhanced) (GB Compatible)" - description "NBA in the Zone (USA) (SGB Enhanced) (GB Compatible)" - rom ( name "NBA in the Zone (USA) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc f6bae9a0 sha1 7f0d5a37956ae58077656a42b26629784c203038 ) + name "NBA in the Zone (USA) (Possible Proto) (SGB Enhanced) (GB Compatible)" + description "NBA in the Zone (USA) (Possible Proto) (SGB Enhanced) (GB Compatible)" + rom ( name "NBA in the Zone (USA) (Possible Proto) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc f6bae9a0 sha1 7f0d5a37956ae58077656a42b26629784c203038 ) ) game ( @@ -39607,15 +42250,21 @@ game ( ) game ( - name "Neclaus' Quest (World) (v1.0) (Aftermarket) (Homebrew)" - description "Neclaus' Quest (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Neclaus' Quest (World) (v1.0) (Aftermarket) (Homebrew).gbc" size 1048576 crc eedefa0c sha1 e63c16fe987fe655408be66198366a0147ac607c ) + name "Neclaus' Quest (World) (GB Compatible) (Aftermarket) (Unl)" + description "Neclaus' Quest (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Neclaus' Quest (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc eedefa0c sha1 e63c16fe987fe655408be66198366a0147ac607c ) ) game ( - name "Neclaus' Quest (World) (v1.1) (Aftermarket) (Homebrew)" - description "Neclaus' Quest (World) (v1.1) (Aftermarket) (Homebrew)" - rom ( name "Neclaus' Quest (World) (v1.1) (Aftermarket) (Homebrew).gbc" size 1048576 crc 53cf930c sha1 bd3272ca7ead64da3f68f774661a560add433b94 ) + name "Neclaus' Quest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Neclaus' Quest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Neclaus' Quest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 53cf930c sha1 bd3272ca7ead64da3f68f774661a560add433b94 ) +) + +game ( + name "Neighbor (World) (GB Compatible) (Aftermarket) (Unl)" + description "Neighbor (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Neighbor (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 705b150f sha1 6258cf6ad167c9ae86609a8e620face1674a7ea7 ) ) game ( @@ -39708,6 +42357,18 @@ game ( rom ( name "Nicktoons Racing (USA).gbc" size 1048576 crc a3f079d4 sha1 8b023f596d9b37ae442578c02c6ba859bc81c5c6 ) ) +game ( + name "Ninja JaJaMaru - The Great World Adventure DX (USA, Europe) (Ninja JaJaMaru Retro Collection) (Switch)" + description "Ninja JaJaMaru - The Great World Adventure DX (USA, Europe) (Ninja JaJaMaru Retro Collection) (Switch)" + rom ( name "Ninja JaJaMaru - The Great World Adventure DX (USA, Europe) (Ninja JaJaMaru Retro Collection) (Switch).gbc" size 262144 crc b5af4ca5 sha1 73efaca14c998dd6790e08f2ce2b6f73e7909ce4 flags verified ) +) + +game ( + name "Ninja Master (World) (Aftermarket) (Unl)" + description "Ninja Master (World) (Aftermarket) (Unl)" + rom ( name "Ninja Master (World) (Aftermarket) (Unl).gbc" size 262144 crc bc550b84 sha1 0def135723ac40e4981c88f8888afbd40a15bb40 ) +) + game ( name "Nintama Rantarou - Ninjutsu Gakuen ni Nyuugaku Shiyou no Dan (Japan)" description "Nintama Rantarou - Ninjutsu Gakuen ni Nyuugaku Shiyou no Dan (Japan)" @@ -39729,7 +42390,7 @@ game ( game ( name "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced) (GB Compatible)" description "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 233862d0 sha1 a61e35306405e41c03b98b162ee14442e77c0da1 ) + rom ( name "Nobunaga no Yabou - Game Boy Ban 2 (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 233862d0 sha1 a61e35306405e41c03b98b162ee14442e77c0da1 flags verified ) ) game ( @@ -39744,6 +42405,12 @@ game ( rom ( name "NSYNC - Get to the Show (USA).gbc" size 1048576 crc f770878b sha1 23b031d03a139c4d963099070b0b290f5f806a6d ) ) +game ( + name "Number Builder (World) (Aftermarket) (Unl)" + description "Number Builder (World) (Aftermarket) (Unl)" + rom ( name "Number Builder (World) (Aftermarket) (Unl).gbc" size 262144 crc b8609d43 sha1 92952b752f50af889db891acc9eed8436ac6b87e ) +) + game ( name "Nushi Tsuri Adventure - Kite no Bouken (Japan) (Rumble Version)" description "Nushi Tsuri Adventure - Kite no Bouken (Japan) (Rumble Version)" @@ -39751,9 +42418,69 @@ game ( ) game ( - name "Nuwang Gedou (Taiwan) (Unl)" - description "Nuwang Gedou (Taiwan) (Unl)" - rom ( name "Nuwang Gedou (Taiwan) (Unl).gbc" size 2097152 crc e1668b49 sha1 37516139aa317a16440379c1dc00bdfc4c1e607a ) + name "Nv Wang Gedou 2000 (Taiwan) (Unl)" + description "Nv Wang Gedou 2000 (Taiwan) (Unl)" + rom ( name "Nv Wang Gedou 2000 (Taiwan) (Unl).gbc" size 2097152 crc e1668b49 sha1 37516139aa317a16440379c1dc00bdfc4c1e607a flags verified ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.2.6) (Beta) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.2.6) (Beta) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.2.6) (Beta) (Aftermarket) (Unl).gbc" size 1048576 crc e983e8d1 sha1 fc2a58d49327c88c895ae6681bde57e1a2687974 flags verified ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.1.2) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.1.2) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.1.2) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc ef42955e sha1 485b4d672d9edda40f9191f5f5cc223046000e67 flags verified ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.2.1) (Beta) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.2.1) (Beta) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.2.1) (Beta) (Aftermarket) (Unl).gbc" size 1048576 crc 581efe4d sha1 125bb0564ee17f8e55046a1c25e53ee9a4254303 ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.2.3) (Beta) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.2.3) (Beta) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.2.3) (Beta) (Aftermarket) (Unl).gbc" size 1048576 crc e26ddbbb sha1 853115369b8ca583d038d00c1dde59b6a74b73a2 ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.2.5) (Beta) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.2.5) (Beta) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.2.5) (Beta) (Aftermarket) (Unl).gbc" size 1048576 crc 1e8ac5b9 sha1 99c11bef7feb17a9e7212cf9b6593478f671bc32 ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (Free Version) (GB Compatible) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (Free Version) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (Free Version) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc f5df28c2 sha1 7b511444e1eb86fffcf93599a78e0e2c44aecc8a ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (Rev 1) (Free Version) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (Rev 1) (Free Version) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (Rev 1) (Free Version) (Aftermarket) (Unl).gbc" size 2097152 crc 63bddc68 sha1 fab777e607bd8aba70eb65829143039dbe6ac08e ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.1.0) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.1.0) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.1.0) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 1f1af42a sha1 ddcdbfa716d716e1b7bb258caaaa7b76d041b5a9 ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.1.2) (Beta) (GB Compatible) (Aftermarket) (Unl) (Alt)" + description "Nyghtmare - The Ninth King (World) (v0.1.2) (Beta) (GB Compatible) (Aftermarket) (Unl) (Alt)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.1.2) (Beta) (GB Compatible) (Aftermarket) (Unl) (Alt).gbc" size 524288 crc 834a8021 sha1 d5af2bf38eda4c181993e992764788003509ebfd ) +) + +game ( + name "Nyghtmare - The Ninth King (World) (v0.1.9) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Nyghtmare - The Ninth King (World) (v0.1.9) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Nyghtmare - The Ninth King (World) (v0.1.9) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 42d9c38c sha1 ae719190cf2f433c359bc425775710f4aa67e860 ) ) game ( @@ -39769,9 +42496,15 @@ game ( ) game ( - name "Oddworld Adventures 2 (USA) (En,Fr,De,Es,It) (GB Compatible)" - description "Oddworld Adventures 2 (USA) (En,Fr,De,Es,It) (GB Compatible)" - rom ( name "Oddworld Adventures 2 (USA) (En,Fr,De,Es,It) (GB Compatible).gbc" size 1048576 crc 5c260d5a sha1 a35ccdf0789ce84df3c12cfe7c4b9b98af08ca9a ) + name "Octopus Stressus (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Octopus Stressus (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Octopus Stressus (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 2c055ef9 sha1 d4fa4e02753a9fe539f70d0927ba5bf9caa02d3c ) +) + +game ( + name "Octopus Stressus (World) (GB Compatible) (Aftermarket) (Unl)" + description "Octopus Stressus (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Octopus Stressus (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 7ed58128 sha1 e543c39f8e55b1788476b94028a54fc2fc9c7ea0 ) ) game ( @@ -39780,6 +42513,18 @@ game ( rom ( name "Oddworld Adventures 2 (Europe) (En,Fr,De,Es,It) (GB Compatible).gbc" size 1048576 crc 4b83b14f sha1 c9d4d1dd1c33a9fa9b54e9f2a7a5f6dd90069b91 flags verified ) ) +game ( + name "Oddworld Adventures 2 (USA) (En,Fr,De,Es,It) (GB Compatible)" + description "Oddworld Adventures 2 (USA) (En,Fr,De,Es,It) (GB Compatible)" + rom ( name "Oddworld Adventures 2 (USA) (En,Fr,De,Es,It) (GB Compatible).gbc" size 1048576 crc 5c260d5a sha1 a35ccdf0789ce84df3c12cfe7c4b9b98af08ca9a ) +) + +game ( + name "Office Combat (World) (GB Compatible) (Aftermarket) (Unl)" + description "Office Combat (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Office Combat (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 9742276d sha1 cd8f18d6e5fabaa130a42e5618e29c5ff26f6a93 ) +) + game ( name "Ohasuta Dance Dance Revolution GB (Japan)" description "Ohasuta Dance Dance Revolution GB (Japan)" @@ -39811,15 +42556,21 @@ game ( ) game ( - name "Olympic Skier (World) (Aftermarket) (Homebrew)" - description "Olympic Skier (World) (Aftermarket) (Homebrew)" - rom ( name "Olympic Skier (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 5e81cef7 sha1 a7a552a9eb984098a67e063c2eca907eec000fc1 ) + name "Olympic Skier (World) (Aftermarket) (Unl)" + description "Olympic Skier (World) (Aftermarket) (Unl)" + rom ( name "Olympic Skier (World) (Aftermarket) (Unl).gbc" size 524288 crc 5e81cef7 sha1 a7a552a9eb984098a67e063c2eca907eec000fc1 ) ) game ( - name "Opossum Country (World) (Aftermarket) (Homebrew)" - description "Opossum Country (World) (Aftermarket) (Homebrew)" - rom ( name "Opossum Country (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 7348bb32 sha1 e63e06d602473206b21138f5322acf86b5b6b9b8 ) + name "One Day (World) (GB Compatible) (Aftermarket) (Unl)" + description "One Day (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "One Day (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc fd52acc7 sha1 bdb5590b61791b89e9afa871d32648d7a66ce1f4 ) +) + +game ( + name "Opossum Country (World) (GB Compatible) (Aftermarket) (Unl)" + description "Opossum Country (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Opossum Country (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 7348bb32 sha1 e63e06d602473206b21138f5322acf86b5b6b9b8 ) ) game ( @@ -39858,6 +42609,12 @@ game ( rom ( name "Ou Dorobou Jing - Devil Version (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 2a39a874 sha1 71797aa125b88614182ce3d0f8252d6ed8cfa08e ) ) +game ( + name "Out on a Limb (World) (Aftermarket) (Unl)" + description "Out on a Limb (World) (Aftermarket) (Unl)" + rom ( name "Out on a Limb (World) (Aftermarket) (Unl).gbc" size 262144 crc a6671528 sha1 f21cb71adcea1029151930eb98c4e9b446e4cfee ) +) + game ( name "Owarai Yoiko no Geemumichi - Oyaji Sagashite 3 Choume (Japan) (SGB Enhanced) (GB Compatible)" description "Owarai Yoiko no Geemumichi - Oyaji Sagashite 3 Choume (Japan) (SGB Enhanced) (GB Compatible)" @@ -39867,7 +42624,7 @@ game ( game ( name "Pac-Man - Special Color Edition (USA) (SGB Enhanced) (GB Compatible)" description "Pac-Man - Special Color Edition (USA) (SGB Enhanced) (GB Compatible)" - rom ( name "Pac-Man - Special Color Edition (USA) (SGB Enhanced) (GB Compatible).gbc" size 262144 crc 3485ef86 sha1 a0a6f55c15dca60350b3a74b1973cc13ff328730 ) + rom ( name "Pac-Man - Special Color Edition (USA) (SGB Enhanced) (GB Compatible).gbc" size 262144 crc 3485ef86 sha1 a0a6f55c15dca60350b3a74b1973cc13ff328730 flags verified ) ) game ( @@ -39894,6 +42651,30 @@ game ( rom ( name "Pachipachi Pachisurou - New Pulsar Hen (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 1e443d1b sha1 969d5352c15e3e5daa891edcda91bd48a8380308 ) ) +game ( + name "Pacifist, The (World) (GB Compatible) (Aftermarket) (Unl)" + description "Pacifist, The (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Pacifist, The (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc c6e83f41 sha1 44b117d94a80617a77abbdcc76d9d69b66efe56b ) +) + +game ( + name "Pacifist, The (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl)" + description "Pacifist, The (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Pacifist, The (World) (GB Showdown) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 69483f81 sha1 4d162c9637a20cfc7c92e6ea7a61fad0ed22137a ) +) + +game ( + name "Pact, The (World) (GB Showdown) (Aftermarket) (Unl)" + description "Pact, The (World) (GB Showdown) (Aftermarket) (Unl)" + rom ( name "Pact, The (World) (GB Showdown) (Aftermarket) (Unl).gbc" size 262144 crc 0db301c2 sha1 58ec8f209ed6e33adfb253014ea69ae1ee53c145 ) +) + +game ( + name "Pact, The (World) (Aftermarket) (Unl)" + description "Pact, The (World) (Aftermarket) (Unl)" + rom ( name "Pact, The (World) (Aftermarket) (Unl).gbc" size 262144 crc 304df19a sha1 97af064f9063cd353e55ac0e1f6d1ca8b4a6d2b9 ) +) + game ( name "Painter (Europe) (Unl)" description "Painter (Europe) (Unl)" @@ -39901,9 +42682,9 @@ game ( ) game ( - name "Panik!16 (World) (Aftermarket) (Homebrew)" - description "Panik!16 (World) (Aftermarket) (Homebrew)" - rom ( name "Panik!16 (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 7b31122d sha1 98d74fd64e4f7e835f1101b05816b8938a34a416 ) + name "Panik!16 (World) (Aftermarket) (Unl)" + description "Panik!16 (World) (Aftermarket) (Unl)" + rom ( name "Panik!16 (World) (Aftermarket) (Unl).gbc" size 262144 crc 7b31122d sha1 98d74fd64e4f7e835f1101b05816b8938a34a416 ) ) game ( @@ -39939,7 +42720,7 @@ game ( game ( name "Peugeot - Orbital Diagnostic System (Unknown) (Unl) [b]" description "Peugeot - Orbital Diagnostic System (Unknown) (Unl) [b]" - rom ( name "Peugeot - Orbital Diagnostic System (Unknown) (Unl) [b].gbc" size 32768 crc 731c6ff4 sha1 2d4f9dc954d9485fbd7d402e07edf42beebbeb8c flags baddump ) + rom ( name "Peugeot - Orbital Diagnostic System (Unknown) (Unl) [b].gbc" size 1048576 crc f971fce9 sha1 6bc140722fad759830fd6e4b6ac0b41443795fb2 flags baddump ) ) game ( @@ -39948,6 +42729,12 @@ game ( rom ( name "Peugeot - Orbital Diagnostic System (Unknown) (Alt) (Unl) [b].gbc" size 32768 crc 424912fe sha1 bd5735021e4593ec07082e6197e683496d0ecf0b flags baddump ) ) +game ( + name "Phantom Fright (World) (GB Compatible) (Aftermarket) (Unl)" + description "Phantom Fright (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Phantom Fright (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 154cb547 sha1 3b217c595e6a5b115dc7130123a321049cf01d22 ) +) + game ( name "Phantom Zona (Japan) (SGB Enhanced) (GB Compatible)" description "Phantom Zona (Japan) (SGB Enhanced) (GB Compatible)" @@ -39961,27 +42748,33 @@ game ( ) game ( - name "Pian Wai Zhang Huang Jin Tai Yang - Feng Yin De Yuan Gu Lian Jin Shu (Taiwan) (Unl)" - description "Pian Wai Zhang Huang Jin Tai Yang - Feng Yin De Yuan Gu Lian Jin Shu (Taiwan) (Unl)" - rom ( name "Pian Wai Zhang Huang Jin Tai Yang - Feng Yin De Yuan Gu Lian Jin Shu (Taiwan) (Unl).gbc" size 2097152 crc 0db9fdfa sha1 6d2acdca141001bfefdcbf0076702fec6619e368 ) + name "Pian Wai Zhang - Huangjin Taiyang - Fengyin de Yuangu Lianjin Shu (Taiwan) (Unl)" + description "Pian Wai Zhang - Huangjin Taiyang - Fengyin de Yuangu Lianjin Shu (Taiwan) (Unl)" + rom ( name "Pian Wai Zhang - Huangjin Taiyang - Fengyin de Yuangu Lianjin Shu (Taiwan) (Unl).gbc" size 2097152 crc 0db9fdfa sha1 6d2acdca141001bfefdcbf0076702fec6619e368 ) ) game ( - name "Pie Crust (World) (v1.0) (Homebrew)" - description "Pie Crust (World) (v1.0) (Homebrew)" - rom ( name "Pie Crust (World) (v1.0) (Homebrew).gbc" size 32768 crc f39c8119 sha1 b01cad9652bf1c65151dd8d2bd21251a9cf44d43 ) + name "Piecrust (World) (Unl)" + description "Piecrust (World) (Unl)" + rom ( name "Piecrust (World) (Unl).gbc" size 32768 crc f39c8119 sha1 b01cad9652bf1c65151dd8d2bd21251a9cf44d43 ) ) game ( - name "Pine Creek (World) (En-US,Es-MX,Pt-BR) (Aftermarket) (Homebrew)" - description "Pine Creek (World) (En-US,Es-MX,Pt-BR) (Aftermarket) (Homebrew)" - rom ( name "Pine Creek (World) (En-US,Es-MX,Pt-BR) (Aftermarket) (Homebrew).gbc" size 2097152 crc 189aa999 sha1 2cf46a36502eaf22ac9572fe1136d369fcbe9e46 ) + name "Pilgrim's Peril (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Pilgrim's Peril (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Pilgrim's Peril (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 3c2bafdc sha1 d38f3f5e491dbaed84e88099987712449db9b33d ) ) game ( - name "Pinecone Pizza Party (World) (Prototype) (Aftermarket) (Homebrew)" - description "Pinecone Pizza Party (World) (Prototype) (Aftermarket) (Homebrew)" - rom ( name "Pinecone Pizza Party (World) (Prototype) (Aftermarket) (Homebrew).gbc" size 262144 crc 1601d6fa sha1 87b4edf0398f0154d7556e3cd96f97b19e699a40 ) + name "Pine Creek (World) (En-US,Es-MX,Pt-BR) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Pine Creek (World) (En-US,Es-MX,Pt-BR) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Pine Creek (World) (En-US,Es-MX,Pt-BR) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 189aa999 sha1 2cf46a36502eaf22ac9572fe1136d369fcbe9e46 ) +) + +game ( + name "Pinecone Pizza Party (World) (Prototype) (GB Compatible) (Aftermarket) (Unl)" + description "Pinecone Pizza Party (World) (Prototype) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Pinecone Pizza Party (World) (Prototype) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 1601d6fa sha1 87b4edf0398f0154d7556e3cd96f97b19e699a40 ) ) game ( @@ -40014,6 +42807,12 @@ game ( rom ( name "Player Manager 2001 (Europe) (En,Fr).gbc" size 1048576 crc 375c35e0 sha1 6e21a85257361be76914f418409124c5bc315429 ) ) +game ( + name "PlayTime (World) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "PlayTime (World) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "PlayTime (World) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 29415ff7 sha1 89b3fd633e8cef3b8523b1ef2a0072db2d7416d7 ) +) + game ( name "Pocket Billiards - Funk the 9 Ball (Japan)" description "Pocket Billiards - Funk the 9 Ball (Japan)" @@ -40123,9 +42922,9 @@ game ( ) game ( - name "Pocket Monster Carbuncle 2003 (USA) (Unl)" - description "Pocket Monster Carbuncle 2003 (USA) (Unl)" - rom ( name "Pocket Monster Carbuncle 2003 (USA) (Unl).gbc" size 2097152 crc 3a0e9b6f sha1 025973627743f2f1ae1ff5b8a3f549cbcc227ef3 ) + name "Pocket Monsters - Crystal Version (Japan)" + description "Pocket Monsters - Crystal Version (Japan)" + rom ( name "Pocket Monsters - Crystal Version (Japan).gbc" size 2097152 crc 270c4ecc sha1 95127b901bbce2407daf43cce9f45d4c27ef635d flags verified ) ) game ( @@ -40134,12 +42933,6 @@ game ( rom ( name "Pocket Monsters - Crystal Version (Taiwan) (Unl).gbc" size 2097152 crc 4b2b8b57 sha1 9a2b381a134bb7ed1b566bb6f94596b57e690a4e ) ) -game ( - name "Pocket Monsters - Crystal Version (Japan)" - description "Pocket Monsters - Crystal Version (Japan)" - rom ( name "Pocket Monsters - Crystal Version (Japan).gbc" size 2097152 crc 270c4ecc sha1 95127b901bbce2407daf43cce9f45d4c27ef635d flags verified ) -) - game ( name "Pocket Monsters Diamond (Taiwan) (En) (Unl)" description "Pocket Monsters Diamond (Taiwan) (En) (Unl)" @@ -40189,9 +42982,9 @@ game ( ) game ( - name "Pocket Music (USA) (En,Fr,De,Es,It) (Proto)" - description "Pocket Music (USA) (En,Fr,De,Es,It) (Proto)" - rom ( name "Pocket Music (USA) (En,Fr,De,Es,It) (Proto).gbc" size 1048576 crc c4387812 sha1 ad547a79af864eb56a18e1c2ad4346eb35df41ed ) + name "Pocket Music (USA) (En,Es) (Proto)" + description "Pocket Music (USA) (En,Es) (Proto)" + rom ( name "Pocket Music (USA) (En,Es) (Proto).gbc" size 1048576 crc c4387812 sha1 ad547a79af864eb56a18e1c2ad4346eb35df41ed ) ) game ( @@ -40261,9 +43054,9 @@ game ( ) game ( - name "Pogo Pete (World) (Aftermarket) (Homebrew)" - description "Pogo Pete (World) (Aftermarket) (Homebrew)" - rom ( name "Pogo Pete (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 3001ed1b sha1 f9dab150843c2b8f300d36b1dd53dd1a22b481a3 ) + name "Pogo Pete (World) (Aftermarket) (Unl)" + description "Pogo Pete (World) (Aftermarket) (Unl)" + rom ( name "Pogo Pete (World) (Aftermarket) (Unl).gbc" size 262144 crc 3001ed1b sha1 f9dab150843c2b8f300d36b1dd53dd1a22b481a3 ) ) game ( @@ -40335,7 +43128,7 @@ game ( game ( name "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible)" description "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible)" - rom ( name "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 576f5ced sha1 76fa60d66b2f22a035adc54c61aad9a415c894cd ) + rom ( name "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 576f5ced sha1 76fa60d66b2f22a035adc54c61aad9a415c894cd flags verified ) ) game ( @@ -40416,6 +43209,12 @@ game ( rom ( name "Pokemon Diamond (Taiwan) (En) (Unl).gbc" size 524288 crc 1b5bef4b sha1 433e7991b706baedf59af8b91bc142ba2f72112f ) ) +game ( + name "Pokemon Gold (Taiwan) (En) (Unl)" + description "Pokemon Gold (Taiwan) (En) (Unl)" + rom ( name "Pokemon Gold (Taiwan) (En) (Unl).gbc" size 1048576 crc 479f3c4e sha1 26503e3262022be29b845a0b2ba555013d8ad12f ) +) + game ( name "Pokemon Gold Version 2 (Taiwan) (Unl)" description "Pokemon Gold Version 2 (Taiwan) (Unl)" @@ -40512,10 +43311,28 @@ game ( rom ( name "Pokemon Vision Jade (Taiwan) (De) (Unl).gbc" size 2097152 crc 2705ca20 sha1 72d5c6b8a570e67e7bce59070417cb89e985efb0 ) ) +game ( + name "Pokettohiro! (World) (v2.0) (Demo) (Aftermarket) (Unl)" + description "Pokettohiro! (World) (v2.0) (Demo) (Aftermarket) (Unl)" + rom ( name "Pokettohiro! (World) (v2.0) (Demo) (Aftermarket) (Unl).gbc" size 1048576 crc 42298fd8 sha1 90c535bf70e2ca7b91af67b8f08865f423c3034f ) +) + +game ( + name "Pokettohiro! (World) (Demo) (Aftermarket) (Unl)" + description "Pokettohiro! (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Pokettohiro! (World) (Demo) (Aftermarket) (Unl).gbc" size 1048576 crc b9e724ef sha1 28a01fd6ea95a146008435c5bc27b51b607bb86b ) +) + game ( name "Polaris SnoCross (USA) (Rumble Version)" description "Polaris SnoCross (USA) (Rumble Version)" - rom ( name "Polaris SnoCross (USA) (Rumble Version).gbc" size 1048576 crc dd8b189e sha1 e893808fe227a1608c0604382d6a0340ec704c3b ) + rom ( name "Polaris SnoCross (USA) (Rumble Version).gbc" size 1048576 crc dd8b189e sha1 e893808fe227a1608c0604382d6a0340ec704c3b flags verified ) +) + +game ( + name "Polaris SnoCross (USA) (Beta) (Rumble Version)" + description "Polaris SnoCross (USA) (Beta) (Rumble Version)" + rom ( name "Polaris SnoCross (USA) (Beta) (Rumble Version).gbc" size 1048576 crc 673623c4 sha1 4176ef1f9fd37156a4cac37a2d146ed2deeb5a7b ) ) game ( @@ -40573,21 +43390,51 @@ game ( ) game ( - name "Powa! (Europe)" - description "Powa! (Europe)" - rom ( name "Powa! (Europe).gbc" size 262144 crc f0191467 sha1 3876f1aa896759f427ad2dc88a48788817e60c06 ) + name "Postie (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Postie (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Postie (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 50393a65 sha1 2c2c6ed8be7a13bf279e435c5984f175c8affcad ) ) game ( - name "Powa! (Japan)" - description "Powa! (Japan)" - rom ( name "Powa! (Japan).gbc" size 262144 crc e8f68acc sha1 156d315b7a2a035d5cd429fb8c7e051e67e83c93 ) + name "Postie (World) (GB Compatible) (Aftermarket) (Unl)" + description "Postie (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Postie (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc ff6bbc83 sha1 3ff236972d1e344eb50e696db3cc090f2b5d28b1 ) ) game ( - name "Powa! (Unknown) (Demo)" - description "Powa! (Unknown) (Demo)" - rom ( name "Powa! (Unknown) (Demo).gbc" size 262144 crc 592b6097 sha1 874d5e4ffc7d36259bef6ec6a86a1de8289b8d54 ) + name "Potbound (World) (2022-09-27) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Potbound (World) (2022-09-27) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Potbound (World) (2022-09-27) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 6da19041 sha1 eb581935ad9223d723fdbc8339c03436df051947 ) +) + +game ( + name "Potbound (World) (2022-09-26) (Proto) (GBJam 10) (GB Compatible) (Aftermarket) (Unl)" + description "Potbound (World) (2022-09-26) (Proto) (GBJam 10) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Potbound (World) (2022-09-26) (Proto) (GBJam 10) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc d0d8386d sha1 fbddf81a1663388ff0efeeb9051e68e0c323c839 ) +) + +game ( + name "POWA! (World) (En) (GB Compatible) (Aftermarket) (Unl)" + description "POWA! (World) (En) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "POWA! (World) (En) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc f0191467 sha1 3876f1aa896759f427ad2dc88a48788817e60c06 flags verified ) +) + +game ( + name "POWA! (World) (Ja) (GB Compatible) (Aftermarket) (Unl)" + description "POWA! (World) (Ja) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "POWA! (World) (Ja) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc e8f68acc sha1 156d315b7a2a035d5cd429fb8c7e051e67e83c93 flags verified ) +) + +game ( + name "POWA! (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "POWA! (World) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "POWA! (World) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 592b6097 sha1 874d5e4ffc7d36259bef6ec6a86a1de8289b8d54 ) +) + +game ( + name "Power Ball - Monster's Quest (World) (v1.04) (Demo) (GB Compatible) (Aftermarket) (Unl)" + description "Power Ball - Monster's Quest (World) (v1.04) (Demo) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Power Ball - Monster's Quest (World) (v1.04) (Demo) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc b01c4ff1 sha1 898dbf10550af7e39b8f7a0818a78083ae40f4fe ) ) game ( @@ -40605,7 +43452,7 @@ game ( game ( name "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced) (GB Compatible)" description "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc c2a4a3eb sha1 5c0ba404cf30296dceeb427a54e3644415c9e8db ) + rom ( name "Power Pro Kun Pocket 2 (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc c2a4a3eb sha1 5c0ba404cf30296dceeb427a54e3644415c9e8db flags verified ) ) game ( @@ -40680,6 +43527,12 @@ game ( rom ( name "Powerpuff Girls, The - Bulle Contre Lui (France).gbc" size 2097152 crc 7085270c sha1 5c1c53b9c002680c2da8b24aa31d4a247586263d ) ) +game ( + name "Powerpuff Girls, The - Il Terribile Mojo Jojo (Italy) (Proto)" + description "Powerpuff Girls, The - Il Terribile Mojo Jojo (Italy) (Proto)" + rom ( name "Powerpuff Girls, The - Il Terribile Mojo Jojo (Italy) (Proto).gbc" size 2097152 crc 5c265103 sha1 5ca837632930689fad9086b772928bf5995193f9 ) +) + game ( name "Powerpuff Girls, The - L'Affreux Mojo Jojo (France)" description "Powerpuff Girls, The - L'Affreux Mojo Jojo (France)" @@ -40746,6 +43599,18 @@ game ( rom ( name "Prince of Persia (Japan) (Proto).gbc" size 1048576 crc d7dbbe1e sha1 6fd97e1f75570e7568b3dc4ab28834813afb4484 ) ) +game ( + name "Princess Poffin and the Spider Invasion! (World) (2023-06-04) (GB Compatible) (Aftermarket) (Unl)" + description "Princess Poffin and the Spider Invasion! (World) (2023-06-04) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Princess Poffin and the Spider Invasion! (World) (2023-06-04) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc a86cada1 sha1 b02096c489c0f36582061d6eb62beb17e8294b61 ) +) + +game ( + name "Princess Poffin and the Spider Invasion! (World) (2023-06-06) (GB Compatible) (Aftermarket) (Unl)" + description "Princess Poffin and the Spider Invasion! (World) (2023-06-06) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Princess Poffin and the Spider Invasion! (World) (2023-06-06) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc e171f327 sha1 b03df48f48529ac1be79699d6f34f324adcfb436 ) +) + game ( name "Pro Darts (USA)" description "Pro Darts (USA)" @@ -40801,15 +43666,21 @@ game ( ) game ( - name "Proof of Destruction (World) (Aftermarket) (Homebrew)" - description "Proof of Destruction (World) (Aftermarket) (Homebrew)" - rom ( name "Proof of Destruction (World) (Aftermarket) (Homebrew).gbc" size 262144 crc fa528f88 sha1 5062f16346c31cae1b13e469cb610ce84d4eecb2 ) + name "Proof of Destruction (World) (Aftermarket) (Unl)" + description "Proof of Destruction (World) (Aftermarket) (Unl)" + rom ( name "Proof of Destruction (World) (Aftermarket) (Unl).gbc" size 262144 crc fa528f88 sha1 5062f16346c31cae1b13e469cb610ce84d4eecb2 ) ) game ( - name "Puchi Carat (USA) (Proto) (SGB Enhanced) (GB Compatible)" - description "Puchi Carat (USA) (Proto) (SGB Enhanced) (GB Compatible)" - rom ( name "Puchi Carat (USA) (Proto) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc a97ea742 sha1 de755124425f9de8bef5eea8026751c54f7f1e00 ) + name "Puchi Carat (USA) (Proto 2) (SGB Enhanced) (GB Compatible)" + description "Puchi Carat (USA) (Proto 2) (SGB Enhanced) (GB Compatible)" + rom ( name "Puchi Carat (USA) (Proto 2) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc a97ea742 sha1 de755124425f9de8bef5eea8026751c54f7f1e00 ) +) + +game ( + name "Puchi Carat (USA) (Proto 1) (SGB Enhanced) (GB Compatible)" + description "Puchi Carat (USA) (Proto 1) (SGB Enhanced) (GB Compatible)" + rom ( name "Puchi Carat (USA) (Proto 1) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc d79b6f46 sha1 b91b121a6951bcc74f0e4af33d41a1fba62f9822 ) ) game ( @@ -40836,6 +43707,12 @@ game ( rom ( name "Pumuckls Abenteuer im Geisterschloss (Germany).gbc" size 1048576 crc 87fcec24 sha1 0fe14ef81b11c854f080e804c5d3cb14601b2794 ) ) +game ( + name "Purple Turtles (World) (Aftermarket) (Unl)" + description "Purple Turtles (World) (Aftermarket) (Unl)" + rom ( name "Purple Turtles (World) (Aftermarket) (Unl).gbc" size 262144 crc 471277df sha1 a73cb69d1fb42f45f3649c4d1b4775e98fe35b78 ) +) + game ( name "Puyo Puyo Gaiden - Puyo Wars (Japan) (SGB Enhanced) (GB Compatible)" description "Puyo Puyo Gaiden - Puyo Wars (Japan) (SGB Enhanced) (GB Compatible)" @@ -40891,15 +43768,15 @@ game ( ) game ( - name "Qi Long Zhu Z 3 (Taiwan) (Unl)" - description "Qi Long Zhu Z 3 (Taiwan) (Unl)" - rom ( name "Qi Long Zhu Z 3 (Taiwan) (Unl).gbc" size 2097152 crc ccfdd63a sha1 4f3b63cd11522b6fb291661f4d918601d95138e0 ) + name "Qi Tian Dasheng - Sun Wukong (Taiwan) (Unl)" + description "Qi Tian Dasheng - Sun Wukong (Taiwan) (Unl)" + rom ( name "Qi Tian Dasheng - Sun Wukong (Taiwan) (Unl).gbc" size 524288 crc a336c40c sha1 3d7e987f1315242422c0db45c4aea120c1b41429 ) ) game ( - name "Qi Tian Da Sheng - Sun Wu Kong (Taiwan) (Unl)" - description "Qi Tian Da Sheng - Sun Wu Kong (Taiwan) (Unl)" - rom ( name "Qi Tian Da Sheng - Sun Wu Kong (Taiwan) (Unl).gbc" size 524288 crc a336c40c sha1 3d7e987f1315242422c0db45c4aea120c1b41429 ) + name "Qilongzhu Z3 (Taiwan) (Unl)" + description "Qilongzhu Z3 (Taiwan) (Unl)" + rom ( name "Qilongzhu Z3 (Taiwan) (Unl).gbc" size 2097152 crc ccfdd63a sha1 4f3b63cd11522b6fb291661f4d918601d95138e0 ) ) game ( @@ -40921,9 +43798,15 @@ game ( ) game ( - name "Quan Ba Tian Xia (Taiwan) (Unl)" - description "Quan Ba Tian Xia (Taiwan) (Unl)" - rom ( name "Quan Ba Tian Xia (Taiwan) (Unl).gbc" size 4194304 crc 2c922ed6 sha1 c19eb98a9745d2c2ce9e4dba3f17ae0b3dee0f49 ) + name "Quan Ba Tianxia (Taiwan) (Unl)" + description "Quan Ba Tianxia (Taiwan) (Unl)" + rom ( name "Quan Ba Tianxia (Taiwan) (Unl).gbc" size 4194304 crc 2c922ed6 sha1 c19eb98a9745d2c2ce9e4dba3f17ae0b3dee0f49 ) +) + +game ( + name "Quartet (World) (GB Compatible) (Aftermarket) (Unl)" + description "Quartet (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Quartet (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc 46743216 sha1 bf866b438a602af386f8fad02727b4084edf6047 ) ) game ( @@ -40938,6 +43821,12 @@ game ( rom ( name "Quest - Fantasy Challenge (USA) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 98285775 sha1 86812b2cd4304dc7ee2dd3faf16737b0414aaffb ) ) +game ( + name "Quest Arrest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Quest Arrest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Quest Arrest (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 9ac546d5 sha1 25b3a21135bfc7587c096b10f4a20d8b3095d721 ) +) + game ( name "Quest for Camelot (Europe) (En,Fr,De,Es,It,Nl) (SGB Enhanced) (GB Compatible)" description "Quest for Camelot (Europe) (En,Fr,De,Es,It,Nl) (SGB Enhanced) (GB Compatible)" @@ -40992,6 +43881,12 @@ game ( rom ( name "Radikal Bikers (Europe) (En,Fr,De,Es) (Proto).gbc" size 2097152 crc 81e25d37 sha1 f16aa29669b15153a63ad92388768e38aa18fbf8 ) ) +game ( + name "Raffles (World) (Aftermarket) (Unl)" + description "Raffles (World) (Aftermarket) (Unl)" + rom ( name "Raffles (World) (Aftermarket) (Unl).gbc" size 262144 crc e41d6472 sha1 4b5eb518ff52c235c674e0695fdde2b8b01f58fa ) +) + game ( name "Rainbow Islands (Europe) (En,Fr,De,Es,It)" description "Rainbow Islands (Europe) (En,Fr,De,Es,It)" @@ -41040,6 +43935,12 @@ game ( rom ( name "Rats! (USA) (En,Es) (GB Compatible).gbc" size 524288 crc 17635ad1 sha1 5e423dfab8221b69a641d2e535ebfe1e3759a2e4 ) ) +game ( + name "Ravenia (World) (GB Compatible) (Aftermarket) (Unl)" + description "Ravenia (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ravenia (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 09196a32 sha1 8218ad22b29fb32c66430a17a97775dd30b2f34b flags verified ) +) + game ( name "Rayman (Europe) (En,Fr,De,Es,It,Nl)" description "Rayman (Europe) (En,Fr,De,Es,It,Nl)" @@ -41118,6 +44019,30 @@ game ( rom ( name "Real Pro Yakyuu! - Pacific League Hen (Japan) (SGB Enhanced) (GB Compatible).gbc" size 524288 crc 16b81c36 sha1 a7a2cd7bbb4cae171b5f2c798293afefe2882afc ) ) +game ( + name "Remen Gaoxiao - Shuma Guaishou III (Taiwan) (Unl)" + description "Remen Gaoxiao - Shuma Guaishou III (Taiwan) (Unl)" + rom ( name "Remen Gaoxiao - Shuma Guaishou III (Taiwan) (Unl).gbc" size 524288 crc 9f64fb1c sha1 b8d6910c8b5c1cab044c61679bbbc4f213648f56 ) +) + +game ( + name "Repugnant Bounty (World) (Demo) (GB Compo 2021) (GB Compatible) (Aftermarket) (Unl)" + description "Repugnant Bounty (World) (Demo) (GB Compo 2021) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Repugnant Bounty (World) (Demo) (GB Compo 2021) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc e92034d8 sha1 14b9614cea9be7d5c6e12aece692582ba2ca2b75 flags verified ) +) + +game ( + name "Repugnant Bounty (World) (v0.1.023) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Repugnant Bounty (World) (v0.1.023) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Repugnant Bounty (World) (v0.1.023) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 3a1b1d83 sha1 4dda0cce6907de94eeae3f11a40238c3f5155ca7 ) +) + +game ( + name "Repugnant Bounty (World) (Demo) (Aftermarket) (Unl)" + description "Repugnant Bounty (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Repugnant Bounty (World) (Demo) (Aftermarket) (Unl).gbc" size 2097152 crc f8c7f180 sha1 07674d42f5d4efaec14750ae56d8f28c4b54c020 flags verified ) +) + game ( name "Rescue Heroes - Fire Frenzy (USA)" description "Rescue Heroes - Fire Frenzy (USA)" @@ -41160,6 +44085,18 @@ game ( rom ( name "Resident Evil Gaiden (USA).gbc" size 2097152 crc f8c5021b sha1 a302cddc085d65ca778153e2a591bd648ce963c9 ) ) +game ( + name "Retro Quiz Tower (World) (GB Compatible) (Aftermarket) (Unl)" + description "Retro Quiz Tower (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Retro Quiz Tower (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 8bd98942 sha1 3a5dbafa829e57089de8cfc93c806f7ee023ff1b ) +) + +game ( + name "Retro Quiz Tower (World) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + description "Retro Quiz Tower (World) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Retro Quiz Tower (World) (v1.2) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc c761189c sha1 f7f18d83218b66b9d1cd7267d6d4acfd4eded6c7 ) +) + game ( name "Return of the Ninja (Europe)" description "Return of the Ninja (Europe)" @@ -41185,9 +44122,9 @@ game ( ) game ( - name "Rig Attack (World) (Aftermarket) (Homebrew)" - description "Rig Attack (World) (Aftermarket) (Homebrew)" - rom ( name "Rig Attack (World) (Aftermarket) (Homebrew).gbc" size 262144 crc d013d775 sha1 90bfd921c986abff4555b761cedc90ec36c43fff ) + name "Rig Attack (World) (Aftermarket) (Unl)" + description "Rig Attack (World) (Aftermarket) (Unl)" + rom ( name "Rig Attack (World) (Aftermarket) (Unl).gbc" size 262144 crc d013d775 sha1 90bfd921c986abff4555b761cedc90ec36c43fff ) ) game ( @@ -41196,6 +44133,12 @@ game ( rom ( name "Rip-Tide Racer (Europe) (En,Fr,De,Es,It) (GB Compatible).gbc" size 1048576 crc ab8c3a31 sha1 3354d6e79b8094bbaa4ef48eb8bd2b0774c46e1a ) ) +game ( + name "River Styx Round-Up (World) (GB Compatible) (Aftermarket) (Unl)" + description "River Styx Round-Up (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "River Styx Round-Up (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc ae3f980b sha1 67f63517eacfea22922d07be0efc5fc8f8b8a1d2 ) +) + game ( name "Road Champs - BXS Stunt Biking (USA, Europe)" description "Road Champs - BXS Stunt Biking (USA, Europe)" @@ -41233,9 +44176,15 @@ game ( ) game ( - name "Robin to the Rescue (World) (Aftermarket) (Homebrew)" - description "Robin to the Rescue (World) (Aftermarket) (Homebrew)" - rom ( name "Robin to the Rescue (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 9cd52c18 sha1 ef3bea9ed0de41e311b5f15fccbb0f451848d56c ) + name "Robin to the Rescue (World) (Aftermarket) (Unl)" + description "Robin to the Rescue (World) (Aftermarket) (Unl)" + rom ( name "Robin to the Rescue (World) (Aftermarket) (Unl).gbc" size 262144 crc 9cd52c18 sha1 ef3bea9ed0de41e311b5f15fccbb0f451848d56c ) +) + +game ( + name "Robo Knight (World) (Aftermarket) (Unl)" + description "Robo Knight (World) (Aftermarket) (Unl)" + rom ( name "Robo Knight (World) (Aftermarket) (Unl).gbc" size 524288 crc 8d4507f0 sha1 6012f9a3ae6201e363f46a75e0100552ecb91335 ) ) game ( @@ -41253,7 +44202,7 @@ game ( game ( name "Robopon - Sun Version (USA) (SGB Enhanced) (GB Compatible)" description "Robopon - Sun Version (USA) (SGB Enhanced) (GB Compatible)" - rom ( name "Robopon - Sun Version (USA) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 32caef11 sha1 399c928a38a3901b7a1093bd61f5a4d8c05b9771 ) + rom ( name "Robopon - Sun Version (USA) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 32caef11 sha1 399c928a38a3901b7a1093bd61f5a4d8c05b9771 flags verified ) ) game ( @@ -41295,7 +44244,7 @@ game ( game ( name "Rocket Power - Gettin' Air (USA, Europe)" description "Rocket Power - Gettin' Air (USA, Europe)" - rom ( name "Rocket Power - Gettin' Air (USA, Europe).gbc" size 1048576 crc 7025eb63 sha1 d9c5c22f1f5a2a922cb2b39d5e8f3df31c1155d7 ) + rom ( name "Rocket Power - Gettin' Air (USA, Europe).gbc" size 1048576 crc 7025eb63 sha1 d9c5c22f1f5a2a922cb2b39d5e8f3df31c1155d7 flags verified ) ) game ( @@ -41305,9 +44254,9 @@ game ( ) game ( - name "Rockman (World) (Aftermarket) (Homebrew)" - description "Rockman (World) (Aftermarket) (Homebrew)" - rom ( name "Rockman (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 490b5676 sha1 6f78200acb6698e268e26c1912d64a002cbd3d89 ) + name "Rockman (World) (Aftermarket) (Unl)" + description "Rockman (World) (Aftermarket) (Unl)" + rom ( name "Rockman (World) (Aftermarket) (Unl).gbc" size 262144 crc 490b5676 sha1 6f78200acb6698e268e26c1912d64a002cbd3d89 ) ) game ( @@ -41425,27 +44374,33 @@ game ( ) game ( - name "RPG Tsukuru GB (Japan) (Rev 1) (NP)" - description "RPG Tsukuru GB (Japan) (Rev 1) (NP)" - rom ( name "RPG Tsukuru GB (Japan) (Rev 1) (NP).gbc" size 2097152 crc 57f82031 sha1 f4c36b3cbb13d3cbaaa81e97b0636c4515ce501e ) + name "RPG Tsukuru GB (Japan) (Rev 1) (Possible Proto) (NP)" + description "RPG Tsukuru GB (Japan) (Rev 1) (Possible Proto) (NP)" + rom ( name "RPG Tsukuru GB (Japan) (Rev 1) (Possible Proto) (NP).gbc" size 2097152 crc 57f82031 sha1 f4c36b3cbb13d3cbaaa81e97b0636c4515ce501e ) ) game ( - name "Ruby & Rusty Save the Crows (World) (v1.0) (Aftermarket) (Homebrew)" - description "Ruby & Rusty Save the Crows (World) (v1.0) (Aftermarket) (Homebrew)" - rom ( name "Ruby & Rusty Save the Crows (World) (v1.0) (Aftermarket) (Homebrew).gbc" size 2097152 crc a46baa15 sha1 87dd5a6ccb5db59dae09f1953062420977ad2d92 ) + name "Ruby & Rusty Save the Crows (World) (Beta 1) (GB Compatible) (Aftermarket) (Unl)" + description "Ruby & Rusty Save the Crows (World) (Beta 1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ruby & Rusty Save the Crows (World) (Beta 1) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc a46baa15 sha1 87dd5a6ccb5db59dae09f1953062420977ad2d92 ) ) game ( - name "Ruby & Rusty Save the Crows (World) (v2.0) (Aftermarket) (Homebrew)" - description "Ruby & Rusty Save the Crows (World) (v2.0) (Aftermarket) (Homebrew)" - rom ( name "Ruby & Rusty Save the Crows (World) (v2.0) (Aftermarket) (Homebrew).gbc" size 2097152 crc 5602ca84 sha1 49d692796a6d0f3dcfc988648b446c0934f0e794 ) + name "Ruby & Rusty Save the Crows (World) (Beta 2) (GB Compatible) (Aftermarket) (Unl)" + description "Ruby & Rusty Save the Crows (World) (Beta 2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ruby & Rusty Save the Crows (World) (Beta 2) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 5602ca84 sha1 49d692796a6d0f3dcfc988648b446c0934f0e794 ) ) game ( - name "Ruby & Rusty Save the Crows (World) (Beta 3) (Aftermarket) (Homebrew)" - description "Ruby & Rusty Save the Crows (World) (Beta 3) (Aftermarket) (Homebrew)" - rom ( name "Ruby & Rusty Save the Crows (World) (Beta 3) (Aftermarket) (Homebrew).gbc" size 2097152 crc b2547aa6 sha1 981a464d6e1c9e5ac59549845b41dae4817ed3b8 ) + name "Ruby & Rusty Save the Crows (World) (Beta 3) (GB Compatible) (Aftermarket) (Unl)" + description "Ruby & Rusty Save the Crows (World) (Beta 3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ruby & Rusty Save the Crows (World) (Beta 3) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc b2547aa6 sha1 981a464d6e1c9e5ac59549845b41dae4817ed3b8 ) +) + +game ( + name "Ruby & Rusty Save the Crows (World) (v2.6) (GB Compatible) (Aftermarket) (Unl)" + description "Ruby & Rusty Save the Crows (World) (v2.6) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ruby & Rusty Save the Crows (World) (v2.6) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc c18f82cb sha1 bd8cd5822dcc61f7eb0cf2584c9a5b5a94bde14a ) ) game ( @@ -41457,7 +44412,7 @@ game ( game ( name "Rugrats - Totally Angelica (USA, Europe)" description "Rugrats - Totally Angelica (USA, Europe)" - rom ( name "Rugrats - Totally Angelica (USA, Europe).gbc" size 1048576 crc fc6195ef sha1 d4396a974aee16f74a5a80f4845c24dde5a083d6 ) + rom ( name "Rugrats - Totally Angelica (USA, Europe).gbc" size 1048576 crc fc6195ef sha1 d4396a974aee16f74a5a80f4845c24dde5a083d6 flags verified ) ) game ( @@ -41502,6 +44457,24 @@ game ( rom ( name "Runelords (USA) (Proto).gbc" size 4194304 crc 392af730 sha1 2bdcf8208cd0530c75195fd23f2f7839a3480bff ) ) +game ( + name "RunieStory (World) (GB Showdown) (Aftermarket) (Unl)" + description "RunieStory (World) (GB Showdown) (Aftermarket) (Unl)" + rom ( name "RunieStory (World) (GB Showdown) (Aftermarket) (Unl).gbc" size 2097152 crc 96b1ceec sha1 771135edfbc64f7332a9cbd0d72af7a9d0d71f82 ) +) + +game ( + name "RunieStory (World) (Aftermarket) (Unl)" + description "RunieStory (World) (Aftermarket) (Unl)" + rom ( name "RunieStory (World) (Aftermarket) (Unl).gbc" size 2097152 crc 2249b449 sha1 0f6a391d7e05f66092a98e411069fab8e3f24221 ) +) + +game ( + name "Runner (World) (Aftermarket) (Unl)" + description "Runner (World) (Aftermarket) (Unl)" + rom ( name "Runner (World) (Aftermarket) (Unl).gbc" size 262144 crc 4cd8ccb2 sha1 da735d415ed463a953bac45f4793342bd9be2e96 ) +) + game ( name "Saban's Power Rangers - Lightspeed Rescue (USA, Europe)" description "Saban's Power Rangers - Lightspeed Rescue (USA, Europe)" @@ -41517,7 +44490,7 @@ game ( game ( name "Sabrina - The Animated Series - Spooked! (USA, Europe)" description "Sabrina - The Animated Series - Spooked! (USA, Europe)" - rom ( name "Sabrina - The Animated Series - Spooked! (USA, Europe).gbc" size 1048576 crc 2cf48188 sha1 7a219159ef46c5ef88eb6b478667c2ec80194edc ) + rom ( name "Sabrina - The Animated Series - Spooked! (USA, Europe).gbc" size 1048576 crc 2cf48188 sha1 7a219159ef46c5ef88eb6b478667c2ec80194edc flags verified ) ) game ( @@ -41550,6 +44523,18 @@ game ( rom ( name "Sakura Taisen GB 2 - Thunderbolt Sakusen (Japan).gbc" size 4194304 crc 47636a2c sha1 13092603ea1d54264bc48f02c2796947badb462c ) ) +game ( + name "Sam the Optimistic Hedgehog (World) (2023-01-16) (GB Compatible) (Aftermarket) (Unl)" + description "Sam the Optimistic Hedgehog (World) (2023-01-16) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Sam the Optimistic Hedgehog (World) (2023-01-16) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 4e4af60b sha1 ab8d49a99d02eb5c97d75f62dfb3720eec2b5abd ) +) + +game ( + name "Sam the Optimistic Hedgehog (World) (2023-01-21) (GB Compatible) (Aftermarket) (Unl)" + description "Sam the Optimistic Hedgehog (World) (2023-01-21) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Sam the Optimistic Hedgehog (World) (2023-01-21) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 40dc168d sha1 af25acc86f0eef4ce72199383b96fcb4c9f0115e ) +) + game ( name "Samurai Kid (Japan)" description "Samurai Kid (Japan)" @@ -41569,9 +44554,9 @@ game ( ) game ( - name "San Guo Wu Shang 5 (Taiwan) (Unl)" - description "San Guo Wu Shang 5 (Taiwan) (Unl)" - rom ( name "San Guo Wu Shang 5 (Taiwan) (Unl).gbc" size 2097152 crc 8a64c933 sha1 e97508fa49564d56550ad467f4c543f3f218db76 ) + name "San Guo Wushang 5 (Taiwan) (Unl)" + description "San Guo Wushang 5 (Taiwan) (Unl)" + rom ( name "San Guo Wushang 5 (Taiwan) (Unl).gbc" size 2097152 crc 8a64c933 sha1 e97508fa49564d56550ad467f4c543f3f218db76 ) ) game ( @@ -41622,6 +44607,12 @@ game ( rom ( name "Santa Claus Junior (Europe).gbc" size 1048576 crc a744df64 sha1 ab74474cd63a2c74bf9617907270d26b5d183b89 ) ) +game ( + name "Sapphire Hotel - The Little Tales of (World) (v1.2) (Demo) (MBC5) (GB Compatible) (Aftermarket) (Unl)" + description "Sapphire Hotel - The Little Tales of (World) (v1.2) (Demo) (MBC5) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Sapphire Hotel - The Little Tales of (World) (v1.2) (Demo) (MBC5) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc db928e22 sha1 e175d35e6112c347ecd1e0a379e98f430823ba94 ) +) + game ( name "Saru Puncher (Japan) (SGB Enhanced) (GB Compatible)" description "Saru Puncher (Japan) (SGB Enhanced) (GB Compatible)" @@ -41652,6 +44643,12 @@ game ( rom ( name "Sea-Doo HydroCross (USA) (Proto).gbc" size 1048576 crc fb1783f3 sha1 3612e549ba2a71585fc9a57033c97562386cdea4 ) ) +game ( + name "Second Edition Harry Boy, The - The Secret of the Chamber of Secrets (USA) (Unl)" + description "Second Edition Harry Boy, The - The Secret of the Chamber of Secrets (USA) (Unl)" + rom ( name "Second Edition Harry Boy, The - The Secret of the Chamber of Secrets (USA) (Unl).gbc" size 2097152 crc cba2c784 sha1 99d852998fa84c8c0160cc9dfb2e2165a94756ca ) +) + game ( name "Sei Hai Densetsu (Japan) (SGB Enhanced) (GB Compatible)" description "Sei Hai Densetsu (Japan) (SGB Enhanced) (GB Compatible)" @@ -41742,6 +44739,12 @@ game ( rom ( name "Sewing Machine Operation Software (Europe) (En,Fr,Es,Pt) (Proto) (GB Compatible).gbc" size 1048576 crc e34b5ce8 sha1 500439c5e14400ef2bc45cacf5ff834b70c2acd4 ) ) +game ( + name "SGB Test Program (World) (1994.4) (Demo) (SGB Enhanced)" + description "SGB Test Program (World) (1994.4) (Demo) (SGB Enhanced)" + rom ( name "SGB Test Program (World) (1994.4) (Demo) (SGB Enhanced).gbc" size 49152 crc 8960ac1d sha1 a310a9629ce6ad0a607ac9e985056fe257f305b5 ) +) + game ( name "Sgt. Rock - On the Frontline (USA)" description "Sgt. Rock - On the Frontline (USA)" @@ -41821,9 +44824,21 @@ game ( ) game ( - name "Shao Lin Shi San Gun - Ying Xiong Jiu Zhu (Taiwan) (Zh) (Unl)" - description "Shao Lin Shi San Gun - Ying Xiong Jiu Zhu (Taiwan) (Zh) (Unl)" - rom ( name "Shao Lin Shi San Gun - Ying Xiong Jiu Zhu (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 25a857af sha1 2fbbf4e3a40eda75b0876d207502727f8dacca11 ) + name "Shantae (World) (Switch)" + description "Shantae (World) (Switch)" + rom ( name "Shantae (World) (Switch).gbc" size 4194304 crc 5009b832 sha1 e1cc66f1950d585d5b644bf9720c87a356354e6a ) +) + +game ( + name "Shantae (World) (GBA Enhanced) (Switch)" + description "Shantae (World) (GBA Enhanced) (Switch)" + rom ( name "Shantae (World) (GBA Enhanced) (Switch).gbc" size 4194304 crc 1ef9fa6b sha1 d14e8b0029b0aff52134a4fa6794eea72f25f4a6 ) +) + +game ( + name "Shaolin Shisan Gun - Ying Xiong Jiu Zhu (Taiwan) (Zh) (Unl)" + description "Shaolin Shisan Gun - Ying Xiong Jiu Zhu (Taiwan) (Zh) (Unl)" + rom ( name "Shaolin Shisan Gun - Ying Xiong Jiu Zhu (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 25a857af sha1 2fbbf4e3a40eda75b0876d207502727f8dacca11 ) ) game ( @@ -41832,6 +44847,12 @@ game ( rom ( name "Shaoling Legend - Hero, the Saver (Taiwan) (En) (Unl).gbc" size 2097152 crc a321ff7d sha1 b1194edd0962c50cf909262004a102f01f556723 ) ) +game ( + name "Shark Attack (World) (Aftermarket) (Unl)" + description "Shark Attack (World) (Aftermarket) (Unl)" + rom ( name "Shark Attack (World) (Aftermarket) (Unl).gbc" size 262144 crc cf80a2ba sha1 291f453a185f836fcafbd7e41945a409638980c0 ) +) + game ( name "Shaun Palmer's Pro Snowboarder (USA, Australia)" description "Shaun Palmer's Pro Snowboarder (USA, Australia)" @@ -41845,9 +44866,21 @@ game ( ) game ( - name "Sheng Shou Wu Yu - Shen Long Chuan Shuo (Taiwan) (Unl)" - description "Sheng Shou Wu Yu - Shen Long Chuan Shuo (Taiwan) (Unl)" - rom ( name "Sheng Shou Wu Yu - Shen Long Chuan Shuo (Taiwan) (Unl).gbc" size 1048576 crc 99a6e58a sha1 13bd97249b68eb824858a9d7a6061edf94140ac3 ) + name "Sheng Shou Wuyu - Shenlong Chuanshuo (Taiwan) (Unl)" + description "Sheng Shou Wuyu - Shenlong Chuanshuo (Taiwan) (Unl)" + rom ( name "Sheng Shou Wuyu - Shenlong Chuanshuo (Taiwan) (Unl).gbc" size 1048576 crc 99a6e58a sha1 13bd97249b68eb824858a9d7a6061edf94140ac3 ) +) + +game ( + name "Shenghuo Jiangmo Lu Waizhuan (Taiwan) (Unl)" + description "Shenghuo Jiangmo Lu Waizhuan (Taiwan) (Unl)" + rom ( name "Shenghuo Jiangmo Lu Waizhuan (Taiwan) (Unl).gbc" size 2097152 crc 1066ec96 sha1 394709afedc0632c09fee33785b0c4f00a45d3e6 ) +) + +game ( + name "Shenghuo Jiangmo Lu Waizhuan - Guang Yu An De Lunhui (Taiwan) (Unl)" + description "Shenghuo Jiangmo Lu Waizhuan - Guang Yu An De Lunhui (Taiwan) (Unl)" + rom ( name "Shenghuo Jiangmo Lu Waizhuan - Guang Yu An De Lunhui (Taiwan) (Unl).gbc" size 2097152 crc 808f19d7 sha1 62620a2cb01fe93388adc42da0b7cbaf53c11ba8 ) ) game ( @@ -41856,22 +44889,22 @@ game ( rom ( name "Shengui Diguo Zhi Emo Cheng (Taiwan) (Unl).gbc" size 2097152 crc 1823e24d sha1 3fc2533f71cea3aec6310f5f7c33fa7eac427b99 ) ) -game ( - name "Shi Kong Xing Shou (Taiwan) (Unl)" - description "Shi Kong Xing Shou (Taiwan) (Unl)" - rom ( name "Shi Kong Xing Shou (Taiwan) (Unl).gbc" size 2097152 crc ec970863 sha1 bc43036da01bb1aef4daa9e7316907193285011f ) -) - game ( name "Shi Mian Maifu - Fengyun Pian (Taiwan) (Unl)" description "Shi Mian Maifu - Fengyun Pian (Taiwan) (Unl)" rom ( name "Shi Mian Maifu - Fengyun Pian (Taiwan) (Unl).gbc" size 1048576 crc a5f686c3 sha1 68798ac090df9f5fb1ea9c409adf3dc639bc9842 ) ) +game ( + name "Shikong Xing Shou (Taiwan) (Unl)" + description "Shikong Xing Shou (Taiwan) (Unl)" + rom ( name "Shikong Xing Shou (Taiwan) (Unl).gbc" size 2097152 crc ec970863 sha1 bc43036da01bb1aef4daa9e7316907193285011f ) +) + game ( name "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced) (GB Compatible)" description "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc f90c4977 sha1 b15cbd01a21048d0fd022f0e023ab5d91faaf442 ) + rom ( name "Shin Megami Tensei Devil Children - Aka no Sho (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc f90c4977 sha1 b15cbd01a21048d0fd022f0e023ab5d91faaf442 flags verified ) ) game ( @@ -41925,7 +44958,7 @@ game ( game ( name "Shougi 2 (Japan) (GB Compatible)" description "Shougi 2 (Japan) (GB Compatible)" - rom ( name "Shougi 2 (Japan) (GB Compatible).gbc" size 262144 crc a7748d2b sha1 7c89cebc4dfcf8713c94b0553e4f4d4f8945052f ) + rom ( name "Shougi 2 (Japan) (GB Compatible).gbc" size 262144 crc a7748d2b sha1 7c89cebc4dfcf8713c94b0553e4f4d4f8945052f flags verified ) ) game ( @@ -41940,30 +44973,6 @@ game ( rom ( name "Shrek - Fairy Tale Freakdown (USA, Europe) (En,Fr,De,Es,It).gbc" size 2097152 crc 387e6459 sha1 e6a728cafd14a4df952467f2a7434ff14e53e268 flags verified ) ) -game ( - name "Shu Ma Bao Long - Ge Dou Ban 2003 (Taiwan) (Unl)" - description "Shu Ma Bao Long - Ge Dou Ban 2003 (Taiwan) (Unl)" - rom ( name "Shu Ma Bao Long - Ge Dou Ban 2003 (Taiwan) (Unl).gbc" size 2097152 crc 1219eec6 sha1 4a722c10e3893e04c67a66d0aea401d6d220ec7e ) -) - -game ( - name "Shu Ma Bao Long - Shui Jing Ban II (Taiwan) (Unl)" - description "Shu Ma Bao Long - Shui Jing Ban II (Taiwan) (Unl)" - rom ( name "Shu Ma Bao Long - Shui Jing Ban II (Taiwan) (Unl).gbc" size 2097152 crc b67999ae sha1 435c26f47c4e244e8adb3b7f18f2b1d129e163e9 ) -) - -game ( - name "Shu Ma Bao Long 9 - Bao Long Pian 2002 (Taiwan) (Zh) (Unl)" - description "Shu Ma Bao Long 9 - Bao Long Pian 2002 (Taiwan) (Zh) (Unl)" - rom ( name "Shu Ma Bao Long 9 - Bao Long Pian 2002 (Taiwan) (Zh) (Unl).gbc" size 1048576 crc c10fa909 sha1 bdc4a2ca7170f41bc10b89a2e6e96fb990a44f0b ) -) - -game ( - name "Shu Ma Bao Long Zhuan Ji 10 in 1 (Taiwan) (Unl)" - description "Shu Ma Bao Long Zhuan Ji 10 in 1 (Taiwan) (Unl)" - rom ( name "Shu Ma Bao Long Zhuan Ji 10 in 1 (Taiwan) (Unl).gbc" size 4194304 crc 37603b3a sha1 37366ff0b3a722da867327c62cae6ad0e51d4a12 ) -) - game ( name "Shuihu Shenshou (Taiwan) (Unl)" description "Shuihu Shenshou (Taiwan) (Unl)" @@ -41989,9 +44998,9 @@ game ( ) game ( - name "Shuma Baobei - Chao Mengmeng Fanji Zhan (Taiwan) (Zh)" - description "Shuma Baobei - Chao Mengmeng Fanji Zhan (Taiwan) (Zh)" - rom ( name "Shuma Baobei - Chao Mengmeng Fanji Zhan (Taiwan) (Zh).gbc" size 524288 crc fc844e0e sha1 6abec431a861315fb1b284ff964c2abf933444ae ) + name "Shuma Baobei - Chao Mengmeng Fanji Zhan (Taiwan) (Zh) (Unl)" + description "Shuma Baobei - Chao Mengmeng Fanji Zhan (Taiwan) (Zh) (Unl)" + rom ( name "Shuma Baobei - Chao Mengmeng Fanji Zhan (Taiwan) (Zh) (Unl).gbc" size 524288 crc fc844e0e sha1 6abec431a861315fb1b284ff964c2abf933444ae ) ) game ( @@ -42043,9 +45052,51 @@ game ( ) game ( - name "Shuma Baolong 02 4 (Taiwan) (Zh) (Unl)" - description "Shuma Baolong 02 4 (Taiwan) (Zh) (Unl)" - rom ( name "Shuma Baolong 02 4 (Taiwan) (Zh) (Unl).gbc" size 1048576 crc 2ee18ab2 sha1 839f0880749735ba2113e437f8efede171b7474d ) + name "Shuma Baolong - Shuijing Ban II (Taiwan) (Unl)" + description "Shuma Baolong - Shuijing Ban II (Taiwan) (Unl)" + rom ( name "Shuma Baolong - Shuijing Ban II (Taiwan) (Unl).gbc" size 2097152 crc b67999ae sha1 435c26f47c4e244e8adb3b7f18f2b1d129e163e9 ) +) + +game ( + name "Shuma Baolong 02 4 (Taiwan) (Unl)" + description "Shuma Baolong 02 4 (Taiwan) (Unl)" + rom ( name "Shuma Baolong 02 4 (Taiwan) (Unl).gbc" size 1048576 crc 2ee18ab2 sha1 839f0880749735ba2113e437f8efede171b7474d ) +) + +game ( + name "Shuma Baolong 02 4 (China) (Unl)" + description "Shuma Baolong 02 4 (China) (Unl)" + rom ( name "Shuma Baolong 02 4 (China) (Unl).gbc" size 1048576 crc 6f67dfc6 sha1 5c5d1675188a5f618f9babf2b3848942ce08c659 ) +) + +game ( + name "Shuma Baolong 02 5 (China) (Unl)" + description "Shuma Baolong 02 5 (China) (Unl)" + rom ( name "Shuma Baolong 02 5 (China) (Unl).gbc" size 1048576 crc 5ba9f8b5 sha1 c441fcbdb343e0c3c76803aa55ceb728158a8948 ) +) + +game ( + name "Shuma Baolong 2 (China) (Unl)" + description "Shuma Baolong 2 (China) (Unl)" + rom ( name "Shuma Baolong 2 (China) (Unl).gbc" size 1048576 crc acbfc58f sha1 76b1eccf666ea01320134d88d6f7558c24016ca8 ) +) + +game ( + name "Shuma Baolong 3 (China) (Unl)" + description "Shuma Baolong 3 (China) (Unl)" + rom ( name "Shuma Baolong 3 (China) (Unl).gbc" size 1048576 crc dab66d8c sha1 3902ecd4b233d0dff168a285788843de0b6df05e ) +) + +game ( + name "Shuma Baolong 9 - Baolong Pian (Taiwan) (Zh) (Unl)" + description "Shuma Baolong 9 - Baolong Pian (Taiwan) (Zh) (Unl)" + rom ( name "Shuma Baolong 9 - Baolong Pian (Taiwan) (Zh) (Unl).gbc" size 1048576 crc c10fa909 sha1 bdc4a2ca7170f41bc10b89a2e6e96fb990a44f0b ) +) + +game ( + name "Shuma Baolong Zhuanji 10 in 1 (Taiwan) (Unl)" + description "Shuma Baolong Zhuanji 10 in 1 (Taiwan) (Unl)" + rom ( name "Shuma Baolong Zhuanji 10 in 1 (Taiwan) (Unl).gbc" size 4194304 crc 37603b3a sha1 37366ff0b3a722da867327c62cae6ad0e51d4a12 ) ) game ( @@ -42054,6 +45105,48 @@ game ( rom ( name "Shutokou Racing, The (Japan) (SGB Enhanced) (GB Compatible).gbc" size 131072 crc 36e781cd sha1 0f29818190ea9ce8c242b648ba64d50cc5408e5a ) ) +game ( + name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-12-09) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Silent Hill 2 - 20th Anniversary Demake (World) (2021-12-09) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-12-09) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 599132ec sha1 762087df0e5820f1e50da2a22f9ee3b8d16c3e49 ) +) + +game ( + name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-04-16) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Silent Hill 2 - 20th Anniversary Demake (World) (2021-04-16) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-04-16) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 5370b1bf sha1 966e2d79ab4930039c3d6c43fdbb8cdc068ba347 ) +) + +game ( + name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-08-24) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Silent Hill 2 - 20th Anniversary Demake (World) (2021-08-24) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-08-24) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 16f34bcc sha1 c34e744b9120e3a1b2b054d3708e4ab594726c5a ) +) + +game ( + name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-09-13) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Silent Hill 2 - 20th Anniversary Demake (World) (2021-09-13) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-09-13) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 31ce3f27 sha1 c33d685d5ea5cd6cd954af3bc9ee92719b9578b1 ) +) + +game ( + name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-11-07) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Silent Hill 2 - 20th Anniversary Demake (World) (2021-11-07) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-11-07) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc d54b53cb sha1 08948befa0227b795d00fe60e9eede6a1f56597b ) +) + +game ( + name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-12-03) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "Silent Hill 2 - 20th Anniversary Demake (World) (2021-12-03) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - 20th Anniversary Demake (World) (2021-12-03) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 314be6b5 sha1 37978f85ae92e7d9a53611659513fd360f57a5b1 ) +) + +game ( + name "Silent Hill 2 - Born From a Wish (World) (2023-10-03) (Demo) (Aftermarket) (Unl)" + description "Silent Hill 2 - Born From a Wish (World) (2023-10-03) (Demo) (Aftermarket) (Unl)" + rom ( name "Silent Hill 2 - Born From a Wish (World) (2023-10-03) (Demo) (Aftermarket) (Unl).gbc" size 524288 crc 7ebcdd4e sha1 b99f43719155cafbc3dbd7df0ade281c3c7ba171 ) +) + game ( name "Simpsons, The - Night of the Living Treehouse of Horror (USA, Europe)" description "Simpsons, The - Night of the Living Treehouse of Horror (USA, Europe)" @@ -42061,15 +45154,21 @@ game ( ) game ( - name "Skelby (World) (Aftermarket) (Homebrew)" - description "Skelby (World) (Aftermarket) (Homebrew)" - rom ( name "Skelby (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 6ec6c18c sha1 887555aa7e2e61b68a21020237b7d508bb71aded ) + name "Skelby (World) (Aftermarket) (Unl)" + description "Skelby (World) (Aftermarket) (Unl)" + rom ( name "Skelby (World) (Aftermarket) (Unl).gbc" size 524288 crc 6ec6c18c sha1 887555aa7e2e61b68a21020237b7d508bb71aded ) ) game ( - name "Skycon (World) (Aftermarket) (Homebrew)" - description "Skycon (World) (Aftermarket) (Homebrew)" - rom ( name "Skycon (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 195dbc30 sha1 df29ece6c5f5b14840663495230135dd79c5163a ) + name "Skycon (World) (Aftermarket) (Unl)" + description "Skycon (World) (Aftermarket) (Unl)" + rom ( name "Skycon (World) (Aftermarket) (Unl).gbc" size 524288 crc 195dbc30 sha1 df29ece6c5f5b14840663495230135dd79c5163a ) +) + +game ( + name "Sludge & Sorcery (World) (GB Compatible) (Aftermarket) (Unl)" + description "Sludge & Sorcery (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Sludge & Sorcery (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc c906c5af sha1 0e0d472b282e3ea590e0f126baf633ef0d9298fa ) ) game ( @@ -42084,6 +45183,18 @@ game ( rom ( name "Smurfs Nightmare, The (USA).gbc" size 1048576 crc b50cafe4 sha1 1d0d3512f32176b7035f9c2a77d4636b1d08b349 ) ) +game ( + name "Snail DX, The (World) (GB Compatible) (Aftermarket) (Unl)" + description "Snail DX, The (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Snail DX, The (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 1aecd096 sha1 8ce256d963a55badf71fd45047c173a74d76a92c ) +) + +game ( + name "Snail DX, The (World) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + description "Snail DX, The (World) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Snail DX, The (World) (v1.2) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 6cf39388 sha1 9cf5a1d3e8119303a1f4b04b8f4d8b683aee699e ) +) + game ( name "Snobow Champion (Japan)" description "Snobow Champion (Japan)" @@ -42114,6 +45225,12 @@ game ( rom ( name "Snoopy Tennis (Europe) (En,Fr,De,Es,It,Nl) (Beta).gbc" size 1048576 crc 49db04a6 sha1 03adc2731945bc86588fffedfee2050a00679ce6 ) ) +game ( + name "Snooze (World) (GB Compatible) (Aftermarket) (Unl)" + description "Snooze (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Snooze (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc b246095f sha1 b7fdcc006c9c06dd391ee26d44b278d9d3793f6d ) +) + game ( name "Snow White and the Seven Dwarfs (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da)" description "Snow White and the Seven Dwarfs (Europe) (En,Fr,De,Es,It,Nl,Sv,No,Da)" @@ -42138,6 +45255,12 @@ game ( rom ( name "Soccer Manager (Europe) (En,Fr,De,Es).gbc" size 1048576 crc 237ecef9 sha1 353eb6aaf40a78ebf1bca9298726d068a5986efa ) ) +game ( + name "Sofia the Witch - Curse of the Monster Moon (World) (Demo) (Aftermarket) (Unl)" + description "Sofia the Witch - Curse of the Monster Moon (World) (Demo) (Aftermarket) (Unl)" + rom ( name "Sofia the Witch - Curse of the Monster Moon (World) (Demo) (Aftermarket) (Unl).gbc" size 2097152 crc 9e864f1c sha1 ce5dc23c04ff18dfac2367e53d241e81c4bbc3a3 ) +) + game ( name "Solomon (Japan)" description "Solomon (Japan)" @@ -42258,6 +45381,12 @@ game ( rom ( name "Spawn (USA).gbc" size 2097152 crc 72fcb0ad sha1 4f816eec1b5dc79928ade9f3a3c687b8aa5b2f87 ) ) +game ( + name "Spectipede (World) (Aftermarket) (Unl)" + description "Spectipede (World) (Aftermarket) (Unl)" + rom ( name "Spectipede (World) (Aftermarket) (Unl).gbc" size 262144 crc 9c33f76e sha1 834a450d9ceb78b9d89d551300d4d0ea08cd8a6a ) +) + game ( name "Speedy Gonzales - Aztec Adventure (USA, Europe) (GB Compatible)" description "Speedy Gonzales - Aztec Adventure (USA, Europe) (GB Compatible)" @@ -42300,6 +45429,12 @@ game ( rom ( name "Spider-Man 3 - Movie Version (USA) (Unl).gbc" size 2097152 crc 2c0d43a9 sha1 8a6b6a1300db59b86ddf87599cfc8edd2e52e2b0 ) ) +game ( + name "Spiky Harold (World) (Aftermarket) (Unl)" + description "Spiky Harold (World) (Aftermarket) (Unl)" + rom ( name "Spiky Harold (World) (Aftermarket) (Unl).gbc" size 262144 crc 7e9eda35 sha1 486d294b8cf226876581d543e3a08018321bc402 ) +) + game ( name "Spirou - The Robot Invasion (Europe) (En,Fr,De,Es,It,Nl,Da)" description "Spirou - The Robot Invasion (Europe) (En,Fr,De,Es,It,Nl,Da)" @@ -42360,6 +45495,12 @@ game ( rom ( name "Star Heritage (Europe) (Proto) (Password Version).gbc" size 1048576 crc b39b4532 sha1 6eb2c27e2eedb22b4055ded87fce0621d460fe5b ) ) +game ( + name "Star Hunt (World) (GB Compatible) (Aftermarket) (Unl)" + description "Star Hunt (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Star Hunt (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 29320841 sha1 890fda255106ea64bac4973e2e9f4b31bb925d35 ) +) + game ( name "Star Ocean - Blue Sphere (Japan) (SGB Enhanced) (GB Compatible)" description "Star Ocean - Blue Sphere (Japan) (SGB Enhanced) (GB Compatible)" @@ -42396,6 +45537,24 @@ game ( rom ( name "Star Wars Episode I - Racer (USA, Europe) (Rumble Version).gbc" size 2097152 crc 0ebc5758 sha1 c0613d654a4382f0c50fd4d389d3a6aeef4d5207 flags verified ) ) +game ( + name "StarFox - Grounded (World) (GB Compatible) (Aftermarket) (Unl)" + description "StarFox - Grounded (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "StarFox - Grounded (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 82658661 sha1 dd45b0e3f346ce33668d49092b29a44597686061 ) +) + +game ( + name "Stars of Zureon (World) (Proto 2) (GB Compatible) (Aftermarket) (Unl)" + description "Stars of Zureon (World) (Proto 2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Stars of Zureon (World) (Proto 2) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc ce90a95b sha1 75457c5affd0c126f2c916e857950b5cde46a95e ) +) + +game ( + name "Stars of Zureon (World) (Proto 1) (GB Compatible) (Aftermarket) (Unl)" + description "Stars of Zureon (World) (Proto 1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Stars of Zureon (World) (Proto 1) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc b3a04b44 sha1 b16f21b46dfe4e6ce0368e3c5a3fae397274ebbf ) +) + game ( name "Startled 911 (Taiwan) (En) (Unl)" description "Startled 911 (Taiwan) (En) (Unl)" @@ -42403,9 +45562,9 @@ game ( ) game ( - name "Stellar Wars (World) (Aftermarket) (Homebrew)" - description "Stellar Wars (World) (Aftermarket) (Homebrew)" - rom ( name "Stellar Wars (World) (Aftermarket) (Homebrew).gbc" size 262144 crc e0b96256 sha1 ba2d10a2a5f3f073aea11e26ae5c53c9cf7866f8 ) + name "Stellar Wars (World) (Aftermarket) (Unl)" + description "Stellar Wars (World) (Aftermarket) (Unl)" + rom ( name "Stellar Wars (World) (Aftermarket) (Unl).gbc" size 262144 crc e0b96256 sha1 ba2d10a2a5f3f073aea11e26ae5c53c9cf7866f8 ) ) game ( @@ -42456,12 +45615,30 @@ game ( rom ( name "Stuart Little - The Journey Home (USA, Europe).gbc" size 1048576 crc eb273887 sha1 d3c31e41709c54af328787036db1b98997f508ea ) ) +game ( + name "Suicide Run (World) (GB Compatible) (Aftermarket) (Unl)" + description "Suicide Run (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Suicide Run (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 2dc3fdae sha1 a551d904c4af661bd4b6e88063cb5541900117b0 ) +) + +game ( + name "Suicide Run (World) (Aftermarket) (Unl)" + description "Suicide Run (World) (Aftermarket) (Unl)" + rom ( name "Suicide Run (World) (Aftermarket) (Unl).gbc" size 262144 crc d29ab1aa sha1 df373f58e51155e32fb81825a9082150f6d263c8 ) +) + game ( name "Super 16 in 1 (Taiwan) (En) (Sachen) (Unl)" description "Super 16 in 1 (Taiwan) (En) (Sachen) (Unl)" rom ( name "Super 16 in 1 (Taiwan) (En) (Sachen) (Unl).gbc" size 2097152 crc 6a99a079 sha1 bcb683600278094e4d40a7da0226b83ec1f92c81 ) ) +game ( + name "Super 21 in 1 - New GB Rumble (Taiwan) (Unl)" + description "Super 21 in 1 - New GB Rumble (Taiwan) (Unl)" + rom ( name "Super 21 in 1 - New GB Rumble (Taiwan) (Unl).gbc" size 2097152 crc 21746216 sha1 829cc0fcd4b96cf5cac909a7c0697583f4c62241 ) +) + game ( name "Super 6 in 1 (Taiwan) (En,Zh) (6B-001, Sachen) (Unl)" description "Super 6 in 1 (Taiwan) (En,Zh) (6B-001, Sachen) (Unl)" @@ -42498,6 +45675,12 @@ game ( rom ( name "Super Breakout! (USA) (GB Compatible).gbc" size 1048576 crc 52f51cb5 sha1 8c795b6d8ebc3a796821a6b2879f3e5cebf9215c ) ) +game ( + name "Super Bunny Mission (World) (GB Compatible) (Aftermarket) (Unl)" + description "Super Bunny Mission (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Super Bunny Mission (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc c47330e2 sha1 6151286e93b2e2fb92f583371e650e36ab91aaf7 ) +) + game ( name "Super Chinese Fighter EX (Japan)" description "Super Chinese Fighter EX (Japan)" @@ -42513,7 +45696,7 @@ game ( game ( name "Super Donkey Kong 5 (Taiwan) (En) (Rumble Version) (Unl)" description "Super Donkey Kong 5 (Taiwan) (En) (Rumble Version) (Unl)" - rom ( name "Super Donkey Kong 5 (Taiwan) (En) (Rumble Version) (Unl).gbc" size 524288 crc d44c9806 sha1 c761dca73b520711b3205e11091e2bf8d4fd7549 ) + rom ( name "Super Donkey Kong 5 (Taiwan) (En) (Rumble Version) (Unl).gbc" size 524288 crc d44c9806 sha1 c761dca73b520711b3205e11091e2bf8d4fd7549 flags verified ) ) game ( @@ -42528,6 +45711,12 @@ game ( rom ( name "Super Fighters 99 (Taiwan) (SGB Enhanced) (Unl).gbc" size 2097152 crc ce41b1bb sha1 e5af8afdce844f02c4128748067933840a759773 ) ) +game ( + name "Super Fighters S (Taiwan) (GB Compatible) (Unl)" + description "Super Fighters S (Taiwan) (GB Compatible) (Unl)" + rom ( name "Super Fighters S (Taiwan) (GB Compatible) (Unl).gbc" size 2097152 crc 64db799a sha1 ef0bf0feaf9e2bdfb10acd469e915266655adb43 ) +) + game ( name "Super Gals! Kotobuki Ran (Japan)" description "Super Gals! Kotobuki Ran (Japan)" @@ -42541,9 +45730,39 @@ game ( ) game ( - name "Super Jacked Up Tomato Face Johnson (World) (Aftermarket) (Homebrew)" - description "Super Jacked Up Tomato Face Johnson (World) (Aftermarket) (Homebrew)" - rom ( name "Super Jacked Up Tomato Face Johnson (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 87956ddf sha1 b23320d5d3fde2a55b301f7bea324833c31c32d5 ) + name "Super Gran (World) (Aftermarket) (Unl)" + description "Super Gran (World) (Aftermarket) (Unl)" + rom ( name "Super Gran (World) (Aftermarket) (Unl).gbc" size 262144 crc 98ee2e8a sha1 5afe9c7ab1b9d86048a570e7a37a0c244cb84e43 ) +) + +game ( + name "Super Impostor Bros. (World) (GB Compatible) (Aftermarket) (Unl)" + description "Super Impostor Bros. (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Super Impostor Bros. (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc a38d702f sha1 301f93da4e5b0cd8dc3f1bf3e66e38176b8a909b ) +) + +game ( + name "Super Jacked Up Tomato Face Johnson (World) (v2.2) (Aftermarket) (Unl)" + description "Super Jacked Up Tomato Face Johnson (World) (v2.2) (Aftermarket) (Unl)" + rom ( name "Super Jacked Up Tomato Face Johnson (World) (v2.2) (Aftermarket) (Unl).gbc" size 524288 crc 8e1f6bb0 sha1 27522a35211b0f015fa9550c2520f1da1c346886 ) +) + +game ( + name "Super Jacked Up Tomato Face Johnson (World) (v2.3) (Aftermarket) (Unl)" + description "Super Jacked Up Tomato Face Johnson (World) (v2.3) (Aftermarket) (Unl)" + rom ( name "Super Jacked Up Tomato Face Johnson (World) (v2.3) (Aftermarket) (Unl).gbc" size 524288 crc f9731ee2 sha1 23855b95d04a6c7c6d2ce7977bb31dbe6c0e68a0 ) +) + +game ( + name "Super Jacked Up Tomato Face Johnson (World) (Jam Version) (Aftermarket) (Unl)" + description "Super Jacked Up Tomato Face Johnson (World) (Jam Version) (Aftermarket) (Unl)" + rom ( name "Super Jacked Up Tomato Face Johnson (World) (Jam Version) (Aftermarket) (Unl).gbc" size 524288 crc 87956ddf sha1 b23320d5d3fde2a55b301f7bea324833c31c32d5 ) +) + +game ( + name "Super JetPak DX (World) (GB Compatible) (Aftermarket)" + description "Super JetPak DX (World) (GB Compatible) (Aftermarket)" + rom ( name "Super JetPak DX (World) (GB Compatible) (Aftermarket).gbc" size 131072 crc 22def6f9 sha1 e7438db01fbbdeea2404dbf3d093370421ec4e1c flags verified ) ) game ( @@ -42571,9 +45790,9 @@ game ( ) game ( - name "Super Mario Bros. Deluxe (Japan) (En) (Rev 1) (NP)" - description "Super Mario Bros. Deluxe (Japan) (En) (Rev 1) (NP)" - rom ( name "Super Mario Bros. Deluxe (Japan) (En) (Rev 1) (NP).gbc" size 1048576 crc f4e91f63 sha1 e61d564e1ff19eb4b7c62a6cd96214f2bca4b01d ) + name "Super Mario Bros. Deluxe (Japan) (Rev 1) (NP)" + description "Super Mario Bros. Deluxe (Japan) (Rev 1) (NP)" + rom ( name "Super Mario Bros. Deluxe (Japan) (Rev 1) (NP).gbc" size 1048576 crc f4e91f63 sha1 e61d564e1ff19eb4b7c62a6cd96214f2bca4b01d ) ) game ( @@ -42673,9 +45892,9 @@ game ( ) game ( - name "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP)" - description "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP)" - rom ( name "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP).gbc" size 1048576 crc bd366d22 sha1 505ffc930057719cf28560333342dfd6944c15da ) + name "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (Rev 1) (Possible Proto) (SGB Enhanced, GB Compatible) (NP)" + description "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (Rev 1) (Possible Proto) (SGB Enhanced, GB Compatible) (NP)" + rom ( name "Survival Kids 2 - Dasshutsu!! Futago-Jima! (Japan) (Rev 1) (Possible Proto) (SGB Enhanced, GB Compatible) (NP).gbc" size 1048576 crc bd366d22 sha1 505ffc930057719cf28560333342dfd6944c15da ) ) game ( @@ -42732,6 +45951,18 @@ game ( rom ( name "SWiV (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc 44d30b7a sha1 7e037008eabf01fa647cdfb0d5c88766a6f77423 ) ) +game ( + name "Swordbird Song - The Iron Owl Tower (World) (v3.1) (GB Compatible) (Aftermarket) (Unl)" + description "Swordbird Song - The Iron Owl Tower (World) (v3.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Swordbird Song - The Iron Owl Tower (World) (v3.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 64921bb1 sha1 b36ec89e0299c19767cc5c6467fa3664abbc3017 ) +) + +game ( + name "Swordbird Song - The Iron Owl Tower (World) (v3.0) (GB Compatible) (Aftermarket) (Unl)" + description "Swordbird Song - The Iron Owl Tower (World) (v3.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Swordbird Song - The Iron Owl Tower (World) (v3.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc b2b5dc4b sha1 aaa66863b2e68865359d1c0db2047bab6f64f9ee ) +) + game ( name "Sylvanian Families - Otogi no Kuni no Pendant (Japan) (SGB Enhanced) (GB Compatible)" description "Sylvanian Families - Otogi no Kuni no Pendant (Japan) (SGB Enhanced) (GB Compatible)" @@ -42745,9 +45976,9 @@ game ( ) game ( - name "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan) (Rev 1) (NP)" - description "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan) (Rev 1) (NP)" - rom ( name "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan) (Rev 1) (NP).gbc" size 2097152 crc ad6f3bdf sha1 c96044d57a2367ffb7b2325aa8d0c9b659e0aaba ) + name "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan) (Rev 1) (Possible Proto)" + description "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan) (Rev 1) (Possible Proto)" + rom ( name "Sylvanian Families 2 - Irozuku Mori no Fantasy (Japan) (Rev 1) (Possible Proto).gbc" size 2097152 crc ad6f3bdf sha1 c96044d57a2367ffb7b2325aa8d0c9b659e0aaba ) ) game ( @@ -42816,10 +46047,22 @@ game ( rom ( name "Taito Memorial - Chase H.Q. - Secret Police (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 6a0c272d sha1 d6d90667ebf295016f01b4604ab03ab5b1876d00 ) ) +game ( + name "Tales of Monsterland (World) (v2.83) (GB Compatible) (Aftermarket) (Unl)" + description "Tales of Monsterland (World) (v2.83) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Tales of Monsterland (World) (v2.83) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc a685f89a sha1 15a709d4300464b03ede4d774ce69cfb699c0fcf ) +) + game ( name "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced) (GB Compatible)" description "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced) (GB Compatible)" - rom ( name "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 725cf31c sha1 ef322f4160ceebd8da67758ebd73225190af6d23 ) + rom ( name "Tales of Phantasia - Narikiri Dungeon (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 725cf31c sha1 ef322f4160ceebd8da67758ebd73225190af6d23 flags verified ) +) + +game ( + name "Tamarindo's Freaking Dinner DX (World) (Aftermarket) (Unl)" + description "Tamarindo's Freaking Dinner DX (World) (Aftermarket) (Unl)" + rom ( name "Tamarindo's Freaking Dinner DX (World) (Aftermarket) (Unl).gbc" size 262144 crc 257d9201 sha1 d78e0b03a3915531e780057c4ad7ed2b3f849825 ) ) game ( @@ -42828,10 +46071,16 @@ game ( rom ( name "Tanimura Hitoshi Ryuu Pachinko Kouryaku Daisakusen - Don Quijote ga Iku (Japan) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc ce8ae58c sha1 f752e96602274a29006425a06086d8ab45e1075c ) ) +game ( + name "Tank Attack (World) (Aftermarket) (Unl)" + description "Tank Attack (World) (Aftermarket) (Unl)" + rom ( name "Tank Attack (World) (Aftermarket) (Unl).gbc" size 262144 crc c77dc518 sha1 4751a6999f4dbe7e66b997372588f6bd15e4d9d0 ) +) + game ( name "Tarzan (France)" description "Tarzan (France)" - rom ( name "Tarzan (France).gbc" size 2097152 crc c503afbb sha1 9a4821570f565f7a1b3c7aba3c7cd2e1c1a0b570 ) + rom ( name "Tarzan (France).gbc" size 2097152 crc c503afbb sha1 9a4821570f565f7a1b3c7aba3c7cd2e1c1a0b570 flags verified ) ) game ( @@ -42882,6 +46131,18 @@ game ( rom ( name "Taxi 3 (France).gbc" size 1048576 crc 2838996f sha1 e43817c673d47b7587f542dcc9f74190c63629ff ) ) +game ( + name "Tazz (World) (2022-10-13) (Aftermarket) (Unl)" + description "Tazz (World) (2022-10-13) (Aftermarket) (Unl)" + rom ( name "Tazz (World) (2022-10-13) (Aftermarket) (Unl).gbc" size 262144 crc 1d97b754 sha1 39226ed715ae8d94f9187c3e5e8a849eac92ca26 ) +) + +game ( + name "Tazz (World) (2022-10-17) (Aftermarket) (Unl)" + description "Tazz (World) (2022-10-17) (Aftermarket) (Unl)" + rom ( name "Tazz (World) (2022-10-17) (Aftermarket) (Unl).gbc" size 262144 crc 6fb0ba23 sha1 543118e54b166ea2b8b5979f8468cc2f5662161f ) +) + game ( name "Tech Deck Skateboarding (USA, Europe)" description "Tech Deck Skateboarding (USA, Europe)" @@ -42973,9 +46234,9 @@ game ( ) game ( - name "Tezhong Budui (Taiwan) (Unl) (Alt)" - description "Tezhong Budui (Taiwan) (Unl) (Alt)" - rom ( name "Tezhong Budui (Taiwan) (Unl) (Alt).gbc" size 1048576 crc bf0028d9 sha1 99f536400bb99892b736f66305e1b11d8229c668 ) + name "Tezhong Budui (Taiwan) (Unl) (Alt) [b]" + description "Tezhong Budui (Taiwan) (Unl) (Alt) [b]" + rom ( name "Tezhong Budui (Taiwan) (Unl) (Alt) [b].gbc" size 1048576 crc bf0028d9 sha1 99f536400bb99892b736f66305e1b11d8229c668 flags baddump ) ) game ( @@ -42990,18 +46251,6 @@ game ( rom ( name "TG Rally 2 (United Kingdom).gbc" size 1048576 crc 795a9992 sha1 906f886c19c4800a7ac2612951e03a092665b22c ) ) -game ( - name "The Powerpuff Girls - Il Terribile Mojo Jojo (Italy) (Proto)" - description "The Powerpuff Girls - Il Terribile Mojo Jojo (Italy) (Proto)" - rom ( name "The Powerpuff Girls - Il Terribile Mojo Jojo (Italy) (Proto).gbc" size 2097152 crc 5c265103 sha1 5ca837632930689fad9086b772928bf5995193f9 ) -) - -game ( - name "The Second Edition Harry Boy - The Secret of the Chamber of Secrets (USA) (Unl)" - description "The Second Edition Harry Boy - The Secret of the Chamber of Secrets (USA) (Unl)" - rom ( name "The Second Edition Harry Boy - The Secret of the Chamber of Secrets (USA) (Unl).gbc" size 2097152 crc cba2c784 sha1 99d852998fa84c8c0160cc9dfb2e2165a94756ca ) -) - game ( name "Three Lions (United Kingdom) (En,Fr,De,Es,It,Nl,Sv) (GB Compatible)" description "Three Lions (United Kingdom) (En,Fr,De,Es,It,Nl,Sv) (GB Compatible)" @@ -43050,6 +46299,18 @@ game ( rom ( name "Tintin au Tibet (Europe) (En,Fr,De,Es,It,Nl,Sv).gbc" size 1048576 crc 6832f38a sha1 eef17d4a827efab90c03083edb0bee534cd64188 ) ) +game ( + name "Tiny Grasshopper Goes Away (World) (En,Hu) (v1.4) (GB Compatible) (Aftermarket) (Unl)" + description "Tiny Grasshopper Goes Away (World) (En,Hu) (v1.4) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Tiny Grasshopper Goes Away (World) (En,Hu) (v1.4) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc af13e718 sha1 307e51664db2101755b6c617f3d81ee58676c485 ) +) + +game ( + name "Tiny Grasshopper Goes Away (World) (En,Hu) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + description "Tiny Grasshopper Goes Away (World) (En,Hu) (v1.2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Tiny Grasshopper Goes Away (World) (En,Hu) (v1.2) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 0518f5aa sha1 85e5cd0cf7a6cc4a5946c93fa8665235a686e554 ) +) + game ( name "Tiny Toon Adventures - Buster Saves the Day (Europe) (En,Fr,De,Es,It)" description "Tiny Toon Adventures - Buster Saves the Day (Europe) (En,Fr,De,Es,It)" @@ -43074,6 +46335,12 @@ game ( rom ( name "Tiny Toon Adventures - Dizzy's Candy Quest (USA) (Proto).gbc" size 1048576 crc 23bb87a5 sha1 4eb0359a278173ae6c12e9452a7a2a9573a58c77 ) ) +game ( + name "Tir Na Nog (World) (Aftermarket) (Unl)" + description "Tir Na Nog (World) (Aftermarket) (Unl)" + rom ( name "Tir Na Nog (World) (Aftermarket) (Unl).gbc" size 1048576 crc 44524c90 sha1 ac712228460e9d4268f90ec4cf9ac2137fa667c4 ) +) + game ( name "Titi - Le Tour du Monde en 80 Chats (France)" description "Titi - Le Tour du Monde en 80 Chats (France)" @@ -43099,9 +46366,9 @@ game ( ) game ( - name "Tobu Tobu Girl Deluxe (World) (GB Compatible) (Aftermarket) (Homebrew)" - description "Tobu Tobu Girl Deluxe (World) (GB Compatible) (Aftermarket) (Homebrew)" - rom ( name "Tobu Tobu Girl Deluxe (World) (GB Compatible) (Aftermarket) (Homebrew).gbc" size 262144 crc 16650a8b sha1 fe6eef70d48dda741f7ad3b6cc5e753e8cd13239 ) + name "Tobu Tobu Girl Deluxe (World) (GB Compatible) (Aftermarket) (Unl)" + description "Tobu Tobu Girl Deluxe (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Tobu Tobu Girl Deluxe (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 16650a8b sha1 fe6eef70d48dda741f7ad3b6cc5e753e8cd13239 ) ) game ( @@ -43179,7 +46446,7 @@ game ( game ( name "Tom Clancy's Rainbow Six (USA, Europe) (En,Fr,De)" description "Tom Clancy's Rainbow Six (USA, Europe) (En,Fr,De)" - rom ( name "Tom Clancy's Rainbow Six (USA, Europe) (En,Fr,De).gbc" size 1048576 crc e72f2683 sha1 7e9e21db84d1bfdab3c604c9e3328f624f86a9b1 ) + rom ( name "Tom Clancy's Rainbow Six (USA, Europe) (En,Fr,De).gbc" size 1048576 crc e72f2683 sha1 7e9e21db84d1bfdab3c604c9e3328f624f86a9b1 flags verified ) ) game ( @@ -43212,6 +46479,12 @@ game ( rom ( name "Tomb Raider 2 (Taiwan) (Unl).gbc" size 4194304 crc 717a5d19 sha1 5b9325b6e322a806677c6ea37a0054381609b99e ) ) +game ( + name "Tomte Trouble (World) (Aftermarket) (Unl)" + description "Tomte Trouble (World) (Aftermarket) (Unl)" + rom ( name "Tomte Trouble (World) (Aftermarket) (Unl).gbc" size 262144 crc a43d6b82 sha1 99730fe00703d655b1c806f49c9e3c2fb3dec58e flags verified ) +) + game ( name "Tonic Trouble (Europe) (En,Fr,De,Es,It,Nl)" description "Tonic Trouble (Europe) (En,Fr,De,Es,It,Nl)" @@ -43381,9 +46654,9 @@ game ( ) game ( - name "Tower of Evil (World) (Aftermarket) (Homebrew)" - description "Tower of Evil (World) (Aftermarket) (Homebrew)" - rom ( name "Tower of Evil (World) (Aftermarket) (Homebrew).gbc" size 524288 crc aeb6e36f sha1 e9a6a007e935afb522c67d355e0354b0fb9af3c6 ) + name "Tower of Evil (World) (Aftermarket) (Unl)" + description "Tower of Evil (World) (Aftermarket) (Unl)" + rom ( name "Tower of Evil (World) (Aftermarket) (Unl).gbc" size 524288 crc aeb6e36f sha1 e9a6a007e935afb522c67d355e0354b0fb9af3c6 ) ) game ( @@ -43441,9 +46714,15 @@ game ( ) game ( - name "Treasure Island Color (World) (Aftermarket) (Homebrew)" - description "Treasure Island Color (World) (Aftermarket) (Homebrew)" - rom ( name "Treasure Island Color (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 4ab0eb5a sha1 3ebddd4e1f5b3a87726ef34a5b7d36de8c722f36 ) + name "Traumatarium (World) (Demo) (2023-06-01) (GB Compatible) (Aftermarket) (Unl)" + description "Traumatarium (World) (Demo) (2023-06-01) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Traumatarium (World) (Demo) (2023-06-01) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc b0a32d51 sha1 4c0d639722d1cd8393e008d174b8f7266d089ead ) +) + +game ( + name "Treasure Island Color (World) (Aftermarket) (Unl)" + description "Treasure Island Color (World) (Aftermarket) (Unl)" + rom ( name "Treasure Island Color (World) (Aftermarket) (Unl).gbc" size 262144 crc 4ab0eb5a sha1 3ebddd4e1f5b3a87726ef34a5b7d36de8c722f36 ) ) game ( @@ -43476,6 +46755,12 @@ game ( rom ( name "Trouballs (USA).gbc" size 524288 crc 260eed04 sha1 dc4d0f608354e7cc32df7501dbacf8c50d70e728 ) ) +game ( + name "Trouble City - Pocket Mission (World) (GB Compatible) (Aftermarket) (Unl)" + description "Trouble City - Pocket Mission (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Trouble City - Pocket Mission (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 4b9143ad sha1 0e51e398d44aaad74a7c622f7818b56a3b34db56 ) +) + game ( name "True Color 25 in 1 (Taiwan) (Unl)" description "True Color 25 in 1 (Taiwan) (Unl)" @@ -43530,12 +46815,24 @@ game ( rom ( name "Turok 3 - Shadow of Oblivion (USA, Europe) (En,Fr,De,Es).gbc" size 1048576 crc 6d48765e sha1 4b240f6b8e3648f2cbafa2fd6ee4e5b508950122 flags verified ) ) +game ( + name "Tutti Frutti (World) (Aftermarket) (Unl)" + description "Tutti Frutti (World) (Aftermarket) (Unl)" + rom ( name "Tutti Frutti (World) (Aftermarket) (Unl).gbc" size 262144 crc ca377ca6 sha1 53d97b93b9d190de40ed2d81e18b4cbe44f99a23 ) +) + game ( name "Tutty (Europe) (Demo)" description "Tutty (Europe) (Demo)" rom ( name "Tutty (Europe) (Demo).gbc" size 131072 crc c4655f0a sha1 51883c4cc1469987483f993e3904da22690faeb9 ) ) +game ( + name "TV-Chan's Great Escape! (World) (Proto) (GB Compatible) (Aftermarket) (Unl)" + description "TV-Chan's Great Escape! (World) (Proto) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "TV-Chan's Great Escape! (World) (Proto) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 01239312 sha1 4f21c3539ef40a7630581fe50533371e0d1a1ba9 ) +) + game ( name "Tweenies - Doodles' Bones (Europe) (En,De,Es,It)" description "Tweenies - Doodles' Bones (Europe) (En,De,Es,It)" @@ -43573,9 +46870,21 @@ game ( ) game ( - name "Tycoon Tex (World) (Aftermarket) (Homebrew)" - description "Tycoon Tex (World) (Aftermarket) (Homebrew)" - rom ( name "Tycoon Tex (World) (Aftermarket) (Homebrew).gbc" size 262144 crc fa8436ba sha1 d37bcd93d647ac7efb761c539785a4ef570cdcc8 ) + name "Tycoon Tex (World) (Aftermarket) (Unl)" + description "Tycoon Tex (World) (Aftermarket) (Unl)" + rom ( name "Tycoon Tex (World) (Aftermarket) (Unl).gbc" size 262144 crc fa8436ba sha1 d37bcd93d647ac7efb761c539785a4ef570cdcc8 ) +) + +game ( + name "Tynesoft Commodore 16 Classics (World) (Aftermarket) (Unl)" + description "Tynesoft Commodore 16 Classics (World) (Aftermarket) (Unl)" + rom ( name "Tynesoft Commodore 16 Classics (World) (Aftermarket) (Unl).gbc" size 2097152 crc 8067298a sha1 e44280161ca9d482fae08de844ccc9754abf68b0 ) +) + +game ( + name "Tynesoft Commodore 16 Classics II (World) (Aftermarket) (Unl)" + description "Tynesoft Commodore 16 Classics II (World) (Aftermarket) (Unl)" + rom ( name "Tynesoft Commodore 16 Classics II (World) (Aftermarket) (Unl).gbc" size 1048576 crc 0ce45101 sha1 f61677146ef67b026c636742f0109b8c478d0942 ) ) game ( @@ -43644,6 +46953,24 @@ game ( rom ( name "Ultimate Surfing (USA).gbc" size 1048576 crc e84df1f0 sha1 264c19ab212d938839306f7e8230d5caee3cf3e7 ) ) +game ( + name "Unearthed (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + description "Unearthed (World) (v1.3) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Unearthed (World) (v1.3) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc 29bb9238 sha1 39fbfb220e9be0120090f770249049b3f3583f64 ) +) + +game ( + name "Ungrateful Son, The (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Ungrateful Son, The (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Ungrateful Son, The (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 977b54f4 sha1 016dde406896d827dcad682d40b52d0e9eeefa88 ) +) + +game ( + name "Unholy Friend (World) (GB Compatible) (Aftermarket) (Unl)" + description "Unholy Friend (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Unholy Friend (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 36e4ff4c sha1 b5c9b5f07e31729678637d883b2564c1448b0e57 ) +) + game ( name "Uno (Europe) (En,Fr,De,Es,It,Nl) (GB Compatible)" description "Uno (Europe) (En,Fr,De,Es,It,Nl) (GB Compatible)" @@ -43656,6 +46983,12 @@ game ( rom ( name "Uno (USA) (GB Compatible).gbc" size 1048576 crc f026d509 sha1 20868148461618d1195570775b183a065781ce35 ) ) +game ( + name "UXB (World) (Aftermarket) (Unl)" + description "UXB (World) (Aftermarket) (Unl)" + rom ( name "UXB (World) (Aftermarket) (Unl).gbc" size 262144 crc dd42be4c sha1 6ef7abb689b1c75f613ed253644fbb0f377b7a95 ) +) + game ( name "V-Rally - Championship Edition (Europe) (En,Fr,De,Es)" description "V-Rally - Championship Edition (Europe) (En,Fr,De,Es)" @@ -43674,6 +47007,12 @@ game ( rom ( name "V-Rally - Edition 99 (USA) (En,Fr,Es).gbc" size 1048576 crc da300c6c sha1 638266c9d2d16486c2ed00510176112071b05e2c ) ) +game ( + name "Varmit (World) (Aftermarket) (Unl)" + description "Varmit (World) (Aftermarket) (Unl)" + rom ( name "Varmit (World) (Aftermarket) (Unl).gbc" size 2097152 crc e4827006 sha1 b61876c714c47f62a77304b79f6e34b8d0e7f8a2 ) +) + game ( name "Vegas Games (Europe) (En,Fr,De)" description "Vegas Games (Europe) (En,Fr,De)" @@ -43716,12 +47055,24 @@ game ( rom ( name "Visiteurs, Les (France) (GB Compatible).gbc" size 1048576 crc d843f898 sha1 307b5d80fd7def049d446bf3406ec8d57dfee93d ) ) +game ( + name "VOX (World) (Aftermarket) (Unl)" + description "VOX (World) (Aftermarket) (Unl)" + rom ( name "VOX (World) (Aftermarket) (Unl).gbc" size 262144 crc 346561fb sha1 54a03c77653a19eb1b0d8a6ac82f498f83f35ef2 ) +) + game ( name "VR Sports - Powerboat Racing (USA) (Proto)" description "VR Sports - Powerboat Racing (USA) (Proto)" rom ( name "VR Sports - Powerboat Racing (USA) (Proto).gbc" size 1048576 crc cff671f1 sha1 1c77f032cdd373bfa108ea82c463f8f9f6874c71 ) ) +game ( + name "Wacky Painter (World) (Aftermarket) (Unl)" + description "Wacky Painter (World) (Aftermarket) (Unl)" + rom ( name "Wacky Painter (World) (Aftermarket) (Unl).gbc" size 262144 crc 09daa18d sha1 5425dc675101d63bea03b1c8f46f86fe200ad392 ) +) + game ( name "Wacky Races (Europe) (En,Fr,De,Es,It,Nl)" description "Wacky Races (Europe) (En,Fr,De,Es,It,Nl)" @@ -43734,6 +47085,12 @@ game ( rom ( name "Wacky Races (USA) (En,Fr,Es).gbc" size 1048576 crc 543abb1b sha1 3ec148027d0e5a075d7a4597232e64215c060fa7 ) ) +game ( + name "Wai Xing Tanxian Zhi Xingqiu Dazhan (Taiwan) (Unl)" + description "Wai Xing Tanxian Zhi Xingqiu Dazhan (Taiwan) (Unl)" + rom ( name "Wai Xing Tanxian Zhi Xingqiu Dazhan (Taiwan) (Unl).gbc" size 2097152 crc 4e600093 sha1 32067be39f0bdc354c31a7a02f24ba00b61ae4f1 flags verified ) +) + game ( name "Walt Disney World Quest - Magical Racing Tour (Europe) (Fr,De,Es)" description "Walt Disney World Quest - Magical Racing Tour (Europe) (Fr,De,Es)" @@ -43746,6 +47103,12 @@ game ( rom ( name "Walt Disney World Quest - Magical Racing Tour (USA, Europe).gbc" size 2097152 crc 56beb694 sha1 529289ccfd21397405d08305409c5d9b2119505e ) ) +game ( + name "Wangzu Tiantang (Taiwan) (Unl)" + description "Wangzu Tiantang (Taiwan) (Unl)" + rom ( name "Wangzu Tiantang (Taiwan) (Unl).gbc" size 2097152 crc dee597fc sha1 4e01c94ab55f2d299bd0bea83c0ef500fb9e738c ) +) + game ( name "Warau Inu no Bouken - Silly Go Lucky! (Japan)" description "Warau Inu no Bouken - Silly Go Lucky! (Japan)" @@ -43776,6 +47139,24 @@ game ( rom ( name "Warlocked (USA).gbc" size 2097152 crc cfa0df0f sha1 2f9c05f74476368bd6dbba7d675e7870cf8ca27c flags verified ) ) +game ( + name "Warp Coin Catastrophe, The (World) (GB Compatible) (Aftermarket) (Unl)" + description "Warp Coin Catastrophe, The (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Warp Coin Catastrophe, The (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 1bfe1bf9 sha1 fae12dbbb75ae024e96a7ee21ad4077fdb5ed9a1 ) +) + +game ( + name "Warp Coin Catastrophe, The (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + description "Warp Coin Catastrophe, The (World) (v1.1) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Warp Coin Catastrophe, The (World) (v1.1) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc a381c914 sha1 adf37c5d2f706743b2a4946378df49ed19212039 ) +) + +game ( + name "Warp Coin Catastrophe, The (World) (v1.1.2) (GB Compatible) (Aftermarket) (Unl)" + description "Warp Coin Catastrophe, The (World) (v1.1.2) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Warp Coin Catastrophe, The (World) (v1.1.2) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc 5519c167 sha1 04a53af6a77b884af91f8047d70fc0331bf23913 ) +) + game ( name "Warriors of Might and Magic (USA) (En,Fr,De)" description "Warriors of Might and Magic (USA) (En,Fr,De)" @@ -43819,21 +47200,27 @@ game ( ) game ( - name "Waternet (World) (Aftermarket) (Homebrew)" - description "Waternet (World) (Aftermarket) (Homebrew)" - rom ( name "Waternet (World) (Aftermarket) (Homebrew).gbc" size 32768 crc ef202121 sha1 a11f931b18ba42f48a91e817b7117fa0e3e79518 ) + name "Water Grandprix (World) (Aftermarket) (Unl)" + description "Water Grandprix (World) (Aftermarket) (Unl)" + rom ( name "Water Grandprix (World) (Aftermarket) (Unl).gbc" size 262144 crc 82f54e7e sha1 4029e003870b2afb78a3644e24397d80fc5a3210 ) ) game ( - name "Waternet (World) (Batteryless Save Flash Cartridge Version) (Aftermarket) (Homebrew)" - description "Waternet (World) (Batteryless Save Flash Cartridge Version) (Aftermarket) (Homebrew)" - rom ( name "Waternet (World) (Batteryless Save Flash Cartridge Version) (Aftermarket) (Homebrew).gbc" size 131072 crc 75591760 sha1 e04b01ada17e6924503029cd09a107b7f5d06f17 ) + name "Waternet (World) (GB Compatible) (Aftermarket) (Unl)" + description "Waternet (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Waternet (World) (GB Compatible) (Aftermarket) (Unl).gbc" size 32768 crc ef202121 sha1 a11f931b18ba42f48a91e817b7117fa0e3e79518 ) ) game ( - name "Waternet (World) (Batteryless Generic Save Flash Cartridge Version) (Aftermarket) (Homebrew)" - description "Waternet (World) (Batteryless Generic Save Flash Cartridge Version) (Aftermarket) (Homebrew)" - rom ( name "Waternet (World) (Batteryless Generic Save Flash Cartridge Version) (Aftermarket) (Homebrew).gbc" size 131072 crc f8402dc5 sha1 6feb4178589e87c6267683078201f0630cca23d6 ) + name "Waternet (World) (Batteryless Save Flash Cartridge Version) (GB Compatible) (Aftermarket) (Unl)" + description "Waternet (World) (Batteryless Save Flash Cartridge Version) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Waternet (World) (Batteryless Save Flash Cartridge Version) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 75591760 sha1 e04b01ada17e6924503029cd09a107b7f5d06f17 ) +) + +game ( + name "Waternet (World) (Batteryless Generic Save Flash Cartridge Version) (GB Compatible) (Aftermarket) (Unl)" + description "Waternet (World) (Batteryless Generic Save Flash Cartridge Version) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Waternet (World) (Batteryless Generic Save Flash Cartridge Version) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc f8402dc5 sha1 6feb4178589e87c6267683078201f0630cca23d6 ) ) game ( @@ -43884,6 +47271,24 @@ game ( rom ( name "Wetrix GB (Japan) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc 6215c5b3 sha1 92944052b6e4448abf0103f085998662e0140825 ) ) +game ( + name "What Friends Are For (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + description "What Friends Are For (World) (v2.0) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "What Friends Are For (World) (v2.0) (GB Compatible) (Aftermarket) (Unl).gbc" size 524288 crc 776fc18e sha1 5c4a227c0b2f53e4a349e482c5ba87cb83404f8e ) +) + +game ( + name "What's Updog (World) (2022-11-23) (GB Compatible) (Aftermarket) (Unl)" + description "What's Updog (World) (2022-11-23) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "What's Updog (World) (2022-11-23) (GB Compatible) (Aftermarket) (Unl).gbc" size 262144 crc 2c3d5cbf sha1 a235c0915ac2b826eeb5884d0eccd321236fdb0c ) +) + +game ( + name "Where's My Cake (World) (GB Compatible) (Aftermarket) (Unl)" + description "Where's My Cake (World) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Where's My Cake (World) (GB Compatible) (Aftermarket) (Unl).GBC" size 65536 crc 28114b89 sha1 05b90f0a7e92d42b3008c749d5edeab2a2eae973 ) +) + game ( name "Who Wants to Be a Millionaire - 2nd Edition (USA)" description "Who Wants to Be a Millionaire - 2nd Edition (USA)" @@ -43897,9 +47302,15 @@ game ( ) game ( - name "Wing Warriors (USA) (En,Fr,Es) (Aftermarket) (Homebrew)" - description "Wing Warriors (USA) (En,Fr,Es) (Aftermarket) (Homebrew)" - rom ( name "Wing Warriors (USA) (En,Fr,Es) (Aftermarket) (Homebrew).gbc" size 131072 crc 04e04980 sha1 574cf911d6d8f73699203cd6db42ceec777f7f93 ) + name "Wing Warriors (World) (En,Fr,Es) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Wing Warriors (World) (En,Fr,Es) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Wing Warriors (World) (En,Fr,Es) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 04e04980 sha1 574cf911d6d8f73699203cd6db42ceec777f7f93 ) +) + +game ( + name "Wing Warriors (World) (En,Fr,Es) (GB Compatible) (Aftermarket) (Unl)" + description "Wing Warriors (World) (En,Fr,Es) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Wing Warriors (World) (En,Fr,Es) (GB Compatible) (Aftermarket) (Unl).gbc" size 131072 crc 7328cfb6 sha1 039874148f27ffe533de4ef086f29e724a3217a9 ) ) game ( @@ -43927,9 +47338,9 @@ game ( ) game ( - name "Wizard of Wor (World) (Aftermarket) (Homebrew)" - description "Wizard of Wor (World) (Aftermarket) (Homebrew)" - rom ( name "Wizard of Wor (World) (Aftermarket) (Homebrew).gbc" size 524288 crc 492a9529 sha1 a391646d259a39e7026574145e0a2bacf5f6937b ) + name "Wizard of Wor (World) (Aftermarket) (Unl)" + description "Wizard of Wor (World) (Aftermarket) (Unl)" + rom ( name "Wizard of Wor (World) (Aftermarket) (Unl).gbc" size 524288 crc 492a9529 sha1 a391646d259a39e7026574145e0a2bacf5f6937b ) ) game ( @@ -43999,9 +47410,9 @@ game ( ) game ( - name "World Cup (World) (Aftermarket) (Homebrew)" - description "World Cup (World) (Aftermarket) (Homebrew)" - rom ( name "World Cup (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 56b3ab5f sha1 075890510b3ef205ca50ebbbcf7c0a0c56032cb9 ) + name "World Cup (World) (Aftermarket) (Unl)" + description "World Cup (World) (Aftermarket) (Unl)" + rom ( name "World Cup (World) (Aftermarket) (Unl).gbc" size 262144 crc 56b3ab5f sha1 075890510b3ef205ca50ebbbcf7c0a0c56032cb9 ) ) game ( @@ -44095,27 +47506,33 @@ game ( ) game ( - name "Xi You Ji (Taiwan) (Unl)" - description "Xi You Ji (Taiwan) (Unl)" - rom ( name "Xi You Ji (Taiwan) (Unl).gbc" size 524288 crc f2fc4884 sha1 1f1bb35c47b8bd51edf9511513bb5e5e5e07eec1 ) + name "Xian Dan Chaoren - Ultraman (Taiwan) (Unl)" + description "Xian Dan Chaoren - Ultraman (Taiwan) (Unl)" + rom ( name "Xian Dan Chaoren - Ultraman (Taiwan) (Unl).gbc" size 2097152 crc e81701e8 sha1 2a96a6f2164d80aa81eebdebc0d8f2ff45c3180f ) ) game ( - name "Xiao Tai Ji - Shen Hua Li Xian (Taiwan) (Unl)" - description "Xiao Tai Ji - Shen Hua Li Xian (Taiwan) (Unl)" - rom ( name "Xiao Tai Ji - Shen Hua Li Xian (Taiwan) (Unl).gbc" size 2097152 crc 322c3816 sha1 c89f8d19a52ab5f183a03d65680bf80d1af4a0ee ) + name "Xiao Taiji - Shenhua Lixian (Taiwan) (Unl)" + description "Xiao Taiji - Shenhua Lixian (Taiwan) (Unl)" + rom ( name "Xiao Taiji - Shenhua Lixian (Taiwan) (Unl).gbc" size 2097152 crc 322c3816 sha1 c89f8d19a52ab5f183a03d65680bf80d1af4a0ee ) ) game ( - name "Xin Feng Shen Bang (Taiwan) (Unl)" - description "Xin Feng Shen Bang (Taiwan) (Unl)" - rom ( name "Xin Feng Shen Bang (Taiwan) (Unl).gbc" size 2097152 crc cf8bd780 sha1 99344231bfe3f73dfb95766e0d02a43fbf2e4acc ) + name "Xin Fengkuang A Gei Pao Pao Tang (Taiwan) (Unl)" + description "Xin Fengkuang A Gei Pao Pao Tang (Taiwan) (Unl)" + rom ( name "Xin Fengkuang A Gei Pao Pao Tang (Taiwan) (Unl).gbc" size 2097152 crc e40f757f sha1 6d1332456e10e9da78726415640117262fe53e99 ) ) game ( - name "Xin Guangming Yu Hei'an 2 - Zhushen De Yichan (Taiwan) (Unl)" - description "Xin Guangming Yu Hei'an 2 - Zhushen De Yichan (Taiwan) (Unl)" - rom ( name "Xin Guangming Yu Hei'an 2 - Zhushen De Yichan (Taiwan) (Unl).gbc" size 1048576 crc 0881ed84 sha1 c1985e8a7a241af5a35748528b3e6a9d49b788e7 ) + name "Xin Fengshenbang (Taiwan) (Unl)" + description "Xin Fengshenbang (Taiwan) (Unl)" + rom ( name "Xin Fengshenbang (Taiwan) (Unl).gbc" size 2097152 crc cf8bd780 sha1 99344231bfe3f73dfb95766e0d02a43fbf2e4acc ) +) + +game ( + name "Xin Guangming Yu Hei'an 2 - Zhushen de Yichan (Taiwan) (Unl)" + description "Xin Guangming Yu Hei'an 2 - Zhushen de Yichan (Taiwan) (Unl)" + rom ( name "Xin Guangming Yu Hei'an 2 - Zhushen de Yichan (Taiwan) (Unl).gbc" size 1048576 crc 0881ed84 sha1 c1985e8a7a241af5a35748528b3e6a9d49b788e7 ) ) game ( @@ -44125,15 +47542,27 @@ game ( ) game ( - name "Xin Tiao Hui Yi (Taiwan) (Unl)" - description "Xin Tiao Hui Yi (Taiwan) (Unl)" - rom ( name "Xin Tiao Hui Yi (Taiwan) (Unl).gbc" size 4194304 crc 104968e7 sha1 86e2b619976d22818e4a7c23d7f8a97e9358e51e ) + name "Xin Shiqi Shidai (Taiwan) (Unl)" + description "Xin Shiqi Shidai (Taiwan) (Unl)" + rom ( name "Xin Shiqi Shidai (Taiwan) (Unl).gbc" size 2097152 crc f55342ca sha1 d51300e59c67f88dd2281ca53ae7c035489a723c ) ) game ( - name "Xing Qiu Da Zhan II - Ke Long Ren Zhan Yi (Taiwan) (Unl)" - description "Xing Qiu Da Zhan II - Ke Long Ren Zhan Yi (Taiwan) (Unl)" - rom ( name "Xing Qiu Da Zhan II - Ke Long Ren Zhan Yi (Taiwan) (Unl).gbc" size 2097152 crc 6df86db6 sha1 b6089f2d1064d1851a89ffb20f8e2f8aeb5fe732 ) + name "Xingqiu Dazhan II - Kelong Ren Zhanyi (Taiwan) (Unl)" + description "Xingqiu Dazhan II - Kelong Ren Zhanyi (Taiwan) (Unl)" + rom ( name "Xingqiu Dazhan II - Kelong Ren Zhanyi (Taiwan) (Unl).gbc" size 2097152 crc 6df86db6 sha1 b6089f2d1064d1851a89ffb20f8e2f8aeb5fe732 ) +) + +game ( + name "Xintiao Huiyi (Taiwan) (Unl)" + description "Xintiao Huiyi (Taiwan) (Unl)" + rom ( name "Xintiao Huiyi (Taiwan) (Unl).gbc" size 4194304 crc 104968e7 sha1 86e2b619976d22818e4a7c23d7f8a97e9358e51e ) +) + +game ( + name "Xiyou Ji (Taiwan) (Unl)" + description "Xiyou Ji (Taiwan) (Unl)" + rom ( name "Xiyou Ji (Taiwan) (Unl).gbc" size 524288 crc f2fc4884 sha1 1f1bb35c47b8bd51edf9511513bb5e5e5e07eec1 ) ) game ( @@ -44154,6 +47583,12 @@ game ( rom ( name "Xtreme Sports (USA).gbc" size 4194304 crc 19828751 sha1 ffca13207e6284a3cc16f7f130b68fca87663d08 ) ) +game ( + name "Xtreme Sports (World) (Switch)" + description "Xtreme Sports (World) (Switch)" + rom ( name "Xtreme Sports (World) (Switch).gbc" size 4194304 crc c0437e08 sha1 5da3ad1c5354f29a74c571c2b598da96213afbe1 flags verified ) +) + game ( name "Xtreme Wheels (Europe)" description "Xtreme Wheels (Europe)" @@ -44167,9 +47602,15 @@ game ( ) game ( - name "Xtreme Wheels (Japan) (NP)" - description "Xtreme Wheels (Japan) (NP)" - rom ( name "Xtreme Wheels (Japan) (NP).gbc" size 1048576 crc 30132ab8 sha1 a9f67640d20771e64b1474144fcca9beebdde85d ) + name "Xtreme Wheels (Japan) (Possible Proto) (NP)" + description "Xtreme Wheels (Japan) (Possible Proto) (NP)" + rom ( name "Xtreme Wheels (Japan) (Possible Proto) (NP).gbc" size 1048576 crc 30132ab8 sha1 a9f67640d20771e64b1474144fcca9beebdde85d ) +) + +game ( + name "Xzap (World) (Aftermarket) (Unl)" + description "Xzap (World) (Aftermarket) (Unl)" + rom ( name "Xzap (World) (Aftermarket) (Unl).gbc" size 262144 crc 68ceec9c sha1 35ae73d3ec93c95fdad9a358ccc34bcfc12445b1 ) ) game ( @@ -44184,12 +47625,36 @@ game ( rom ( name "Yars' Revenge (USA, Europe) (GB Compatible).gbc" size 1048576 crc d6a26444 sha1 45fb176d539ae4a65af1f6340a9bd398dd7956d2 ) ) +game ( + name "Year After, The (World) (En,Fr,Pt) (GB Compatible) (Aftermarket) (Unl)" + description "Year After, The (World) (En,Fr,Pt) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Year After, The (World) (En,Fr,Pt) (GB Compatible) (Aftermarket) (Unl).gbc" size 2097152 crc b304833d sha1 c2be46b8230bfcf509d031902c9bf144de97ef58 ) +) + +game ( + name "Year After, The (World) (En) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Year After, The (World) (En) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Year After, The (World) (En) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc f15351c8 sha1 a78ff2eef780287bbdc37df122cfc1c504526662 ) +) + +game ( + name "Year After, The (World) (Pt) (Beta) (GB Compatible) (Aftermarket) (Unl)" + description "Year After, The (World) (Pt) (Beta) (GB Compatible) (Aftermarket) (Unl)" + rom ( name "Year After, The (World) (Pt) (Beta) (GB Compatible) (Aftermarket) (Unl).gbc" size 1048576 crc b70c1c7f sha1 ce25cdf6a6264586423e76e34dc42779d39a1cb1 ) +) + game ( name "Yin Ban Zhongwen RPG Zhanlve + Dongzuo + Yizhi 12 in 1 (Taiwan) (Unl)" description "Yin Ban Zhongwen RPG Zhanlve + Dongzuo + Yizhi 12 in 1 (Taiwan) (Unl)" rom ( name "Yin Ban Zhongwen RPG Zhanlve + Dongzuo + Yizhi 12 in 1 (Taiwan) (Unl).gbc" size 8388608 crc dc3171ad sha1 bfb93e7b4b523ef21c2b98ba9dcb15eb7d4f07e4 ) ) +game ( + name "Yinghan Zidian (Taiwan) (Unl)" + description "Yinghan Zidian (Taiwan) (Unl)" + rom ( name "Yinghan Zidian (Taiwan) (Unl).gbc" size 1048576 crc 87158db6 sha1 5d42f3b769176df569a99c167c67e685c70501e1 ) +) + game ( name "Yingxiong Jian 2 (Taiwan) (Unl)" description "Yingxiong Jian 2 (Taiwan) (Unl)" @@ -44202,6 +47667,18 @@ game ( rom ( name "Yingxiong Tianxia (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 5f2d6317 sha1 41f5f0c11e4e99b7d2d1433b09922a0fd2c48d7f ) ) +game ( + name "Yinyang (Taiwan) (De) (Unl)" + description "Yinyang (Taiwan) (De) (Unl)" + rom ( name "Yinyang (Taiwan) (De) (Unl).gbc" size 2097152 crc 1dd042ab sha1 2da9f06d57dcd397d0333b5d85a26a593acea8b3 ) +) + +game ( + name "Yixing VS Tiexue Zhanshi (Taiwan) (Unl)" + description "Yixing VS Tiexue Zhanshi (Taiwan) (Unl)" + rom ( name "Yixing VS Tiexue Zhanshi (Taiwan) (Unl).gbc" size 2097152 crc 45b048ee sha1 5ab50c386a0d9644f0d0337b6a1db22f5cb6ceb9 ) +) + game ( name "Yogi Bear - Great Balloon Blast (USA)" description "Yogi Bear - Great Balloon Blast (USA)" @@ -44209,9 +47686,9 @@ game ( ) game ( - name "Yong Zhe Dou E Long VIII (Taiwan) (Unl)" - description "Yong Zhe Dou E Long VIII (Taiwan) (Unl)" - rom ( name "Yong Zhe Dou E Long VIII (Taiwan) (Unl).gbc" size 2097152 crc 8b8b84ec sha1 d71788eabb4d2535e31773338523a721e2784bb5 ) + name "Yongzhe Dou E Long VIII (Taiwan) (Unl)" + description "Yongzhe Dou E Long VIII (Taiwan) (Unl)" + rom ( name "Yongzhe Dou E Long VIII (Taiwan) (Unl).gbc" size 2097152 crc 8b8b84ec sha1 d71788eabb4d2535e31773338523a721e2784bb5 ) ) game ( @@ -44298,18 +47775,18 @@ game ( rom ( name "Yu-Gi-Oh! Duel Monsters III - Tri Holy God Advant (Japan).gbc" size 4194304 crc 9f9dbab4 sha1 dc4753a2f12360d921a147287673b4448394a9d3 flags verified ) ) -game ( - name "Yue Nan Zhan Yi 3 (Taiwan) (Unl)" - description "Yue Nan Zhan Yi 3 (Taiwan) (Unl)" - rom ( name "Yue Nan Zhan Yi 3 (Taiwan) (Unl).gbc" size 2097152 crc 9268bb9f sha1 17ceb35582c89303f206eb7e93cbfe8a4c2b5aaa ) -) - game ( name "Yuenan Zhanyi - Chong Jian Tian Ri (Taiwan) (Unl)" description "Yuenan Zhanyi - Chong Jian Tian Ri (Taiwan) (Unl)" rom ( name "Yuenan Zhanyi - Chong Jian Tian Ri (Taiwan) (Unl).gbc" size 2097152 crc c19b912a sha1 09b0f8fe8c7948e847ad01f24d05513c49b77ad5 ) ) +game ( + name "Yuenan Zhanyi 3 (Taiwan) (Unl)" + description "Yuenan Zhanyi 3 (Taiwan) (Unl)" + rom ( name "Yuenan Zhanyi 3 (Taiwan) (Unl).gbc" size 2097152 crc 9268bb9f sha1 17ceb35582c89303f206eb7e93cbfe8a4c2b5aaa ) +) + game ( name "Yuenan Zhanyi X - Shenru Dihou (Taiwan) (Unl)" description "Yuenan Zhanyi X - Shenru Dihou (Taiwan) (Unl)" @@ -44317,9 +47794,15 @@ game ( ) game ( - name "Zap'em (World) (Aftermarket) (Homebrew)" - description "Zap'em (World) (Aftermarket) (Homebrew)" - rom ( name "Zap'em (World) (Aftermarket) (Homebrew).gbc" size 262144 crc 66f17c5e sha1 63d44c8c2492dc32bcf632feb2d994e9af25fc97 ) + name "Zagan Warrior (World) (Aftermarket) (Unl)" + description "Zagan Warrior (World) (Aftermarket) (Unl)" + rom ( name "Zagan Warrior (World) (Aftermarket) (Unl).gbc" size 262144 crc e770f71a sha1 99d9267946e7bf26942a8276863ba50ef0b8f90e ) +) + +game ( + name "Zap'em (World) (Aftermarket) (Unl)" + description "Zap'em (World) (Aftermarket) (Unl)" + rom ( name "Zap'em (World) (Aftermarket) (Unl).gbc" size 262144 crc 66f17c5e sha1 63d44c8c2492dc32bcf632feb2d994e9af25fc97 ) ) game ( @@ -44337,7 +47820,7 @@ game ( game ( name "Zelda no Densetsu - Fushigi no Kinomi - Jikuu no Shou (Japan)" description "Zelda no Densetsu - Fushigi no Kinomi - Jikuu no Shou (Japan)" - rom ( name "Zelda no Densetsu - Fushigi no Kinomi - Jikuu no Shou (Japan).gbc" size 1048576 crc 3272e6f9 sha1 596aa066ccee9fae71643576f7526baa22d26d6d ) + rom ( name "Zelda no Densetsu - Fushigi no Kinomi - Jikuu no Shou (Japan).gbc" size 1048576 crc 3272e6f9 sha1 596aa066ccee9fae71643576f7526baa22d26d6d flags verified ) ) game ( @@ -44349,7 +47832,7 @@ game ( game ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (SGB Enhanced) (GB Compatible)" description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (SGB Enhanced) (GB Compatible)" - rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc bd8a1041 sha1 d3de302d44bdb240bcf55a5dc70f491f5456d721 ) + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (SGB Enhanced) (GB Compatible).gbc" size 1048576 crc bd8a1041 sha1 d3de302d44bdb240bcf55a5dc70f491f5456d721 flags verified ) ) game ( @@ -44365,15 +47848,15 @@ game ( ) game ( - name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05 18.00.56) (GB Compatible)" - description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05 18.00.56) (GB Compatible)" - rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05 18.00.56) (GB Compatible).gbc" size 1048576 crc 11290c31 sha1 8d7ab85686ced1642b9519bcb6a3e157c6bd8938 ) + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05T180056) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05T180056) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05T180056) (GB Compatible).gbc" size 1048576 crc 11290c31 sha1 8d7ab85686ced1642b9519bcb6a3e157c6bd8938 ) ) game ( - name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05 21.55.32) (GB Compatible)" - description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05 21.55.32) (GB Compatible)" - rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05 21.55.32) (GB Compatible).gbc" size 1048576 crc 3c63e083 sha1 a068abd403a1dad70bd9b53d215995f8159aea47 ) + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05T215532) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05T215532) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-05T215532) (GB Compatible).gbc" size 1048576 crc 3c63e083 sha1 a068abd403a1dad70bd9b53d215995f8159aea47 ) ) game ( @@ -44383,9 +47866,93 @@ game ( ) game ( - name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14) (GB Compatible)" - description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14) (GB Compatible)" - rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14) (GB Compatible).gbc" size 1048576 crc 13c76902 sha1 08dea3565740a4b5bd5c13e82adb61e3d5669a31 ) + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14T022124) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14T022124) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14T022124) (GB Compatible).gbc" size 1048576 crc 13c76902 sha1 08dea3565740a4b5bd5c13e82adb61e3d5669a31 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-02) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-02) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-02) (SGB Enhanced).gbc" size 1048576 crc 34ff47ba sha1 5ccc4c05123b4c38d0d93916ae8a0c93fb63f23f ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-03) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-03) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-03) (SGB Enhanced).gbc" size 1048576 crc ac0ef411 sha1 5aeb68b00a3a4f391afb324d9513311cb796a51f ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-04) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-04) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-04) (SGB Enhanced).gbc" size 1048576 crc 260bd98a sha1 ce1e48c82a09de0f93d5a60016318a9116331ccb ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-09-04) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-09-04) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-09-04) (SGB Enhanced).gbc" size 1048576 crc 883ef4ef sha1 87ca50396ba25914131866c74633afbe0007b2fb ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced).gbc" size 1048576 crc 89a4a355 sha1 48931a00f5fec39492c264e9979646e88242c53e ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced) (Alt)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced) (Alt)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced) (Alt).gbc" size 1048576 crc e5312966 sha1 fedd0fa70bbf5039dfec37b8e27674be839c47ca ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced) (Alt 2)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced) (Alt 2)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-08-07) (SGB Enhanced) (Alt 2).gbc" size 1048576 crc 1c374afd sha1 800db3d07a7abcca2138a0c7808cf25386e87712 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-06-15) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-06-15) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-06-15) (GB Compatible).gbc" size 1048576 crc 3fd6c8fc sha1 017b81b26fc37db662063482e3947dfc2d814390 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-06-15) (GB Compatible) (Alt)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-06-15) (GB Compatible) (Alt)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-06-15) (GB Compatible) (Alt).gbc" size 1048576 crc 9367653b sha1 544b803db49d8f312e193e4c105f0762d9e3fbf4 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14T181500) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14T181500) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-07-14T181500) (GB Compatible).gbc" size 1048576 crc 2f884286 sha1 a7cb241de2139ddac5d1172a6ef1184b5fbb827e ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-11-09) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-11-09) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Beta) (1998-11-09) (GB Compatible).gbc" size 1048576 crc 3e5216c3 sha1 0fe1c48e36cb8e6e975c5421bf881c550746d29c ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (Demo) (Special Version 1) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (Demo) (Special Version 1) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (Demo) (Special Version 1) (GB Compatible).gbc" size 1048576 crc e05757f6 sha1 ee2df3c8449187fcd82f2fc830386bfe8144b387 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (Demo) (Special Version 2) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (Demo) (Special Version 2) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 1) (Demo) (Special Version 2) (GB Compatible).gbc" size 1048576 crc e6101132 sha1 515f8d2fcaebe9495fb21f46ec32cce877c35e56 ) +) + +game ( + name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-09-22) (SGB Enhanced) (GB Compatible)" + description "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-09-22) (SGB Enhanced) (GB Compatible)" + rom ( name "Zelda no Densetsu - Yume o Miru Shima DX (Japan) (Rev 2) (Beta) (1999-09-22) (SGB Enhanced) (GB Compatible).gbc" size 1015808 crc c07979bf sha1 4a9ce5ced2234fa668dace888bd5d6130e375985 ) ) game ( @@ -44395,21 +47962,27 @@ game ( ) game ( - name "Zhen San Guo Wu Shuang 2 - Shin Sangokumusou (Taiwan) (Unl)" - description "Zhen San Guo Wu Shuang 2 - Shin Sangokumusou (Taiwan) (Unl)" - rom ( name "Zhen San Guo Wu Shuang 2 - Shin Sangokumusou (Taiwan) (Unl).gbc" size 2097152 crc 95c322c9 sha1 e6ab58d212de83cb18e9eadac4cee5d0f6e4e31f ) + name "Zephyr's Pass (World) (v1.02) (Demo) (Aftermarket) (Unl)" + description "Zephyr's Pass (World) (v1.02) (Demo) (Aftermarket) (Unl)" + rom ( name "Zephyr's Pass (World) (v1.02) (Demo) (Aftermarket) (Unl).gbc" size 2097152 crc db0951d3 sha1 7b74c658f24894659cfda1fc3c7775fd9f7b6013 ) ) game ( - name "Zhi Huan Wang - Shou Bu Qu (Taiwan) (Zh) (Unl)" - description "Zhi Huan Wang - Shou Bu Qu (Taiwan) (Zh) (Unl)" - rom ( name "Zhi Huan Wang - Shou Bu Qu (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 8160b3f5 sha1 97d7e0d05205b02c6cb69e68978a3f0fd2e3fde0 ) + name "Zhen Sanguo Wushuang 2 - Shin Sangokumusou (Taiwan) (Unl)" + description "Zhen Sanguo Wushuang 2 - Shin Sangokumusou (Taiwan) (Unl)" + rom ( name "Zhen Sanguo Wushuang 2 - Shin Sangokumusou (Taiwan) (Unl).gbc" size 2097152 crc 95c322c9 sha1 e6ab58d212de83cb18e9eadac4cee5d0f6e4e31f ) ) game ( - name "Zhi Zhu Xia III - Dian Ying Ban (Taiwan) (Unl)" - description "Zhi Zhu Xia III - Dian Ying Ban (Taiwan) (Unl)" - rom ( name "Zhi Zhu Xia III - Dian Ying Ban (Taiwan) (Unl).gbc" size 2097152 crc d311efcc sha1 9eb0c468d5f898ef7b4d6ff74d7ff497b8c7818d ) + name "Zhihuan Wang - Shoubu Qu (Taiwan) (Zh) (Unl)" + description "Zhihuan Wang - Shoubu Qu (Taiwan) (Zh) (Unl)" + rom ( name "Zhihuan Wang - Shoubu Qu (Taiwan) (Zh) (Unl).gbc" size 2097152 crc 8160b3f5 sha1 97d7e0d05205b02c6cb69e68978a3f0fd2e3fde0 ) +) + +game ( + name "Zhizhu Xia III - Dianying Ban (Taiwan) (Unl)" + description "Zhizhu Xia III - Dianying Ban (Taiwan) (Unl)" + rom ( name "Zhizhu Xia III - Dianying Ban (Taiwan) (Unl).gbc" size 2097152 crc d311efcc sha1 9eb0c468d5f898ef7b4d6ff74d7ff497b8c7818d ) ) game ( @@ -44418,12 +47991,24 @@ game ( rom ( name "Zidane - Football Generation (Europe) (En,Fr,De,Es,It).gbc" size 1048576 crc e96dbfb5 sha1 06385470bb0b4ef6c743ab6a5e7f8d7a97f6100b ) ) +game ( + name "Zidane - Football Generation (Europe) (En,Fr,De,Es,It) (Beta)" + description "Zidane - Football Generation (Europe) (En,Fr,De,Es,It) (Beta)" + rom ( name "Zidane - Football Generation (Europe) (En,Fr,De,Es,It) (Beta).gbc" size 1048576 crc c2fde3c4 sha1 cba5d2fc5dbbe184e9ed58afe8525044bd8ea040 ) +) + game ( name "Zoboomafoo - Playtime in Zobooland (USA)" description "Zoboomafoo - Playtime in Zobooland (USA)" rom ( name "Zoboomafoo - Playtime in Zobooland (USA).gbc" size 1048576 crc 38d91885 sha1 a85a113bc266325f807f110daaf30feeea4b2738 ) ) +game ( + name "Zodiac (World) (Aftermarket) (Unl)" + description "Zodiac (World) (Aftermarket) (Unl)" + rom ( name "Zodiac (World) (Aftermarket) (Unl).gbc" size 262144 crc c4d86c05 sha1 73bd9e6e3bede8de489680ba84129e8fd17abbc0 ) +) + game ( name "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (SGB Enhanced) (GB Compatible)" description "Zoids - Jashin Fukkatsu! Genobreaker Hen (Japan) (SGB Enhanced) (GB Compatible)" @@ -44448,6 +48033,12 @@ game ( rom ( name "Zok Zok Heroes (Japan).gbc" size 2097152 crc c09f9e1b sha1 91ab908fddebd926e7db8d61295a40955b2adc39 ) ) +game ( + name "Zone Control (World) (Aftermarket) (Unl)" + description "Zone Control (World) (Aftermarket) (Unl)" + rom ( name "Zone Control (World) (Aftermarket) (Unl).gbc" size 262144 crc 856ed536 sha1 a191d41fd86a7c17015e04156ffff8222302d36e ) +) + game ( name "Zook Z (USA) (Unl)" description "Zook Z (USA) (Unl)" diff --git a/res/patrons.txt b/res/patrons.txt index c9346ce64..8e61ae237 100644 --- a/res/patrons.txt +++ b/res/patrons.txt @@ -1,16 +1,15 @@ Akatsuki -AVjoyu__Chan Benedikt Feih Brandon Emily A. Bellows -G +EmuDeck gocha Jaime J. Denizard MichaelK__ Miras Absar +Molly Howell +Nic Losby (blurbdust) Petru-Sebastian Toader Stevoisiak -Tyler Jenkins William K. Leung -Zach Zhongchao Qian diff --git a/res/scripts/analog-interpolate.lua b/res/scripts/analog-interpolate.lua new file mode 100644 index 000000000..d9d985a20 --- /dev/null +++ b/res/scripts/analog-interpolate.lua @@ -0,0 +1,77 @@ +local state = {} +state.period = 4 +state.phase = 0 +state.x = 0 +state.y = 0 + +function state.update() + state.phase = state.phase + 1 + if state.phase == state.period then + state.phase = 0 + end + if state.phase == 0 then + if input.activeGamepad then + local x = input.activeGamepad.axes[1] / 30000 + local y = input.activeGamepad.axes[2] / 30000 + -- Map the circle onto a square, since we don't + -- want to have a duty of 1/sqrt(2) on the angles + local theta = math.atan(y, x) + local r = math.sqrt(x * x + y * y) + if theta < math.pi * -3 / 4 then + r = -r / math.cos(theta) + elseif theta < math.pi * -1 / 4 then + r = -r / math.sin(theta) + elseif theta < math.pi * 1 / 4 then + r = r / math.cos(theta) + elseif theta < math.pi * 3 / 4 then + r = r / math.sin(theta) + elseif theta < math.pi * 5 / 4 then + r = -r / math.cos(theta) + end + state.x = math.cos(theta) * r + state.y = math.sin(theta) * r + else + state.x = 0 + state.y = 0 + end + end +end + +function state.read() + emu:clearKeys(0xF0) + if math.floor(math.abs(state.x) * state.period) > state.phase then + if state.x > 0 then + emu:addKey(C.GB_KEY.RIGHT) + else + emu:addKey(C.GB_KEY.LEFT) + end + end + if math.floor(math.abs(state.y) * state.period) > state.phase then + if state.y > 0 then + emu:addKey(C.GB_KEY.DOWN) + else + emu:addKey(C.GB_KEY.UP) + end + end + + -- The duty cycle approach can confuse menus and the like, + -- so the POV hat setting should force a direction on + if input.activeGamepad and #input.activeGamepad.hats > 0 then + local hat = input.activeGamepad.hats[1] + if hat & C.INPUT_DIR.UP ~= 0 then + emu:addKey(C.GB_KEY.UP) + end + if hat & C.INPUT_DIR.DOWN ~= 0 then + emu:addKey(C.GB_KEY.DOWN) + end + if hat & C.INPUT_DIR.LEFT ~= 0 then + emu:addKey(C.GB_KEY.LEFT) + end + if hat & C.INPUT_DIR.RIGHT ~= 0 then + emu:addKey(C.GB_KEY.RIGHT) + end + end +end + +callbacks:add("frame", state.update) +callbacks:add("keysRead", state.read) diff --git a/res/scripts/gamepad-demo.lua b/res/scripts/gamepad-demo.lua new file mode 100644 index 000000000..90327c11c --- /dev/null +++ b/res/scripts/gamepad-demo.lua @@ -0,0 +1,33 @@ +inputBuffer = console:createBuffer("Input") + +function readPad() + inputBuffer:clear() + + if not input.activeGamepad then + inputBuffer:print("No gamepad detected\n") + return + end + + local gamepad = input.activeGamepad + local axes = gamepad.axes + local buttons = gamepad.buttons + local hats = gamepad.hats + + inputBuffer:print(gamepad.visibleName .. "\n") + inputBuffer:print(string.format("%i buttons, %i axes, %i hats\n", #buttons, #axes, #hats)) + + local sbuttons = {} + for k, v in ipairs(buttons) do + if v then + sbuttons[k] = "down" + else + sbuttons[k] = " up" + end + end + + inputBuffer:print(string.format("Buttons: %s\n", table.concat(sbuttons, ", "))) + inputBuffer:print(string.format("Axes: %s\n", table.concat(axes, ", "))) + inputBuffer:print(string.format("Hats: %s\n", table.concat(hats, ", "))) +end + +callbacks:add("frame", readPad) diff --git a/res/scripts/light-oscillate.lua b/res/scripts/light-oscillate.lua new file mode 100644 index 000000000..6a2848842 --- /dev/null +++ b/res/scripts/light-oscillate.lua @@ -0,0 +1,8 @@ +local theta = 0 + +function readLight() + theta = math.fmod(theta + math.pi / 120, math.pi * 2) + return (math.sin(theta) + 1) * 75 +end + +emu:setSolarSensorCallback(readLight) diff --git a/res/scripts/logo-bounce.lua b/res/scripts/logo-bounce.lua new file mode 100644 index 000000000..c8192638c --- /dev/null +++ b/res/scripts/logo-bounce.lua @@ -0,0 +1,44 @@ +math.randomseed(os.time()) +local state = {} +state.logo = image.load(script.dir .. "/logo.png") +state.overlay = canvas:newLayer(state.logo.width, state.logo.height) +state.overlay.image:drawImageOpaque(state.logo, 0, 0) +state.x = math.random() * (canvas:screenWidth() - state.logo.width) +state.y = math.random() * (canvas:screenHeight() - state.logo.height) +state.direction = math.floor(math.random() * 3) +state.speed = 0.5 + +state.overlay:setPosition(math.floor(state.x), math.floor(state.y)) +state.overlay:update() + +function state.update() + if state.direction & 1 == 1 then + state.x = state.x + 1 + if state.x > canvas:screenWidth() - state.logo.width then + state.x = (canvas:screenWidth() - state.logo.width) * 2 - state.x + state.direction = state.direction ~ 1 + end + else + state.x = state.x - 1 + if state.x < 0 then + state.x = -state.x + state.direction = state.direction ~ 1 + end + end + if state.direction & 2 == 2 then + state.y = state.y + 1 + if state.y > canvas:screenHeight() - state.logo.height then + state.y = (canvas:screenHeight() - state.logo.height) * 2 - state.y + state.direction = state.direction ~ 2 + end + else + state.y = state.y - 1 + if state.y < 0 then + state.y = -state.y + state.direction = state.direction ~ 2 + end + end + state.overlay:setPosition(math.floor(state.x), math.floor(state.y)) +end + +callbacks:add("frame", state.update) diff --git a/res/scripts/logo.png b/res/scripts/logo.png new file mode 100644 index 000000000..77ec0693a Binary files /dev/null and b/res/scripts/logo.png differ diff --git a/res/scripts/pokemon.lua b/res/scripts/pokemon.lua index d909396d0..c89fb8e75 100644 --- a/res/scripts/pokemon.lua +++ b/res/scripts/pokemon.lua @@ -174,7 +174,7 @@ function Generation1En._readPartyMon(game, address, nameAddress, otAddress) return mon end -function Generation2En._readBoxMon(game, address, nameAddress, otAddress) +function Generation2En._readBoxMon(game, address, nameAddress, otAddress) local mon = {} mon.species = emu:read8(address + 0) mon.item = emu:read8(address + 1) diff --git a/res/scripts/tilt-random-walk.lua b/res/scripts/tilt-random-walk.lua new file mode 100644 index 000000000..41fc7f04b --- /dev/null +++ b/res/scripts/tilt-random-walk.lua @@ -0,0 +1,20 @@ +local r = 0 +local theta = 0 +local rotation = {} + +math.randomseed() + +function rotation.sample() + theta = math.fmod(theta + math.random() / 20, math.pi * 2) + r = math.min(math.max(r + (math.random() - 0.5) / 50, -1), 1) +end + +function rotation.readTiltX() + return math.cos(theta) * r +end + +function rotation.readTiltY() + return math.sin(theta) * r +end + +emu:setRotationCallbacks(rotation) diff --git a/res/sgb-icon-128.png b/res/sgb-icon-128.png new file mode 100644 index 000000000..473adac4c Binary files /dev/null and b/res/sgb-icon-128.png differ diff --git a/res/sgb-icon-16.png b/res/sgb-icon-16.png new file mode 100644 index 000000000..6a76a156f Binary files /dev/null and b/res/sgb-icon-16.png differ diff --git a/res/sgb-icon-24.png b/res/sgb-icon-24.png new file mode 100644 index 000000000..5b8bd7a0d Binary files /dev/null and b/res/sgb-icon-24.png differ diff --git a/res/sgb-icon-256.png b/res/sgb-icon-256.png new file mode 100644 index 000000000..6e3132c57 Binary files /dev/null and b/res/sgb-icon-256.png differ diff --git a/res/sgb-icon-32.png b/res/sgb-icon-32.png new file mode 100644 index 000000000..ea28b979d Binary files /dev/null and b/res/sgb-icon-32.png differ diff --git a/res/sgb-icon-48.png b/res/sgb-icon-48.png new file mode 100644 index 000000000..3a801c3b9 Binary files /dev/null and b/res/sgb-icon-48.png differ diff --git a/res/sgb-icon-64.png b/res/sgb-icon-64.png new file mode 100644 index 000000000..1c9007dda Binary files /dev/null and b/res/sgb-icon-64.png differ diff --git a/res/sgb-icon.svg b/res/sgb-icon.svg new file mode 100644 index 000000000..ca922f1aa --- /dev/null +++ b/res/sgb-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/res/shaders/gbc-lcd.shader/gbc-lcd-light.fs b/res/shaders/gbc-lcd.shader/gbc-lcd-light.fs new file mode 100644 index 000000000..cb583f4da --- /dev/null +++ b/res/shaders/gbc-lcd.shader/gbc-lcd-light.fs @@ -0,0 +1,119 @@ +/** + * This shader creates a backlight bleeding effect, + * and an internal reflection or ghosting effect. + */ + +varying vec2 texCoord; +uniform sampler2D tex; + +/** + * Determines the color of the backlight bleed. + * Lower values produce less, dimmer light. + * Higher values produce brighter or more colorful light. + * You'll normally want each of these numbers to be close + * to 1, and not normally lower than 0. + */ +uniform vec3 LightColor; + +/** + * Affects the shape of the backlight bleed glow. + * Lower values cause the light bleed to fade out quickly + * from the edges. + * Higher values cause the light bleed to fade out more + * softly and gradually toward the center. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float LightSoftness; + +/** + * Lower values result in a less visible or intense + * backlight bleed. + * Higher values make the backlight bleed more pronounced. + * You'll normally want this to be a number close to 0, + * and not normally higher than 1. + */ +uniform float LightIntensity; + +/** + * Lower values cause the internal reflection or ghosting + * effect to be less visible. + * Higher values cause the effect to be brighter and more + * visible. + * You'll normally want this to be a number close to 0, + * and not normally higher than 1. + */ +uniform float ReflectionBrightness; + +/** + * Lower values have the internal reflection or ghosting + * effect appear offset by a lesser distance. + * Higher values have the effect offset by a greater + * distance. + * You'll normally want each of these numbers to be close + * to 0, and not normally higher than 1. + */ +uniform vec2 ReflectionDistance; + +#define M_PI 3.1415926535897932384626433832795 + +/** + * Helper to compute backlight bleed intensity + * for a texCoord input. + */ +float getLightIntensity(vec2 coord) { + vec2 coordCentered = coord - vec2(0.5, 0.5); + float coordDistCenter = ( + length(coordCentered) / sqrt(0.5) + ); + vec2 coordQuadrant = vec2( + 1.0 - (1.5 * min(coord.x, 1.0 - coord.x)), + 1.0 - (1.5 * min(coord.y, 1.0 - coord.y)) + ); + float lightIntensityEdges = ( + pow(coordQuadrant.x, 5.0) + + pow(coordQuadrant.y, 5.0) + ); + float lightIntensity = ( + (1.0 - LightSoftness) * lightIntensityEdges + + LightSoftness * coordDistCenter + ); + return clamp(lightIntensity, 0.0, 1.0); +} + +/** + * Helper to convert an intensity value into a white + * gray color with that intensity. A radial distortion + * effect with subtle chromatic abberation is applied that + * makes it look a little more like a real old or cheap + * backlight, and also helps to reduce color banding. + */ +vec3 getWhiteVector(float intensity) { + const float DeformAmount = 0.0025; + vec2 texCoordCentered = texCoord - vec2(0.5, 0.5); + float radians = atan(texCoordCentered.y, texCoordCentered.x); + float rot = pow(2.0, 4.0 + floor(6.0 * length(texCoordCentered))); + float deformRed = cos(rot * radians + (2.0 / 3.0 * M_PI)); + float deformGreen = cos(rot * radians); + float deformBlue = cos(rot * radians + (4.0 / 3.0 * M_PI)); + return clamp(vec3( + intensity + (deformRed * DeformAmount), + intensity + (deformGreen * DeformAmount), + intensity + (deformBlue * DeformAmount) + ), 0.0, 1.0); +} + +void main() { + vec3 colorSource = texture2D(tex, texCoord).rgb; + vec3 lightWhiteVector = getWhiteVector(getLightIntensity(texCoord)); + vec3 colorLight = LightColor * lightWhiteVector; + vec3 colorReflection = texture2D(tex, texCoord - ReflectionDistance).rgb; + vec3 colorResult = ( + colorSource + + (colorLight * LightIntensity) + + (colorReflection * ReflectionBrightness) + ); + gl_FragColor = vec4( + colorResult, + 1.0 + ); +} diff --git a/res/shaders/gbc-lcd.shader/gbc-lcd.fs b/res/shaders/gbc-lcd.shader/gbc-lcd.fs new file mode 100644 index 000000000..4b88ad3aa --- /dev/null +++ b/res/shaders/gbc-lcd.shader/gbc-lcd.fs @@ -0,0 +1,421 @@ +/** + * This shader imitates the GameBoy Color subpixel + * arrangement. + */ + +varying vec2 texCoord; +uniform sampler2D tex; +uniform vec2 texSize; + +/** + * Adds a base color to everything. + * Lower values make black colors darker. + * Higher values make black colors lighter. + * You'll normally want each of these numbers to be close + * to 0, and not normally higher than 1. + */ +uniform vec3 BaseColor; + +/** + * Modifies the contrast or saturation of the image. + * Lower values make the image more gray and higher values + * make it more colorful. + * A value of 1 represents a normal, baseline level of + * contrast. + * You'll normally want this to be somewhere around 1. + */ +uniform float SourceContrast; + +/** + * Modifies the luminosity of the image. + * Lower values make the image darker and higher values make + * it lighter. + * A value of 1 represents normal, baseline luminosity. + * You'll normally want this to be somewhere around 1. + */ +uniform float SourceLuminosity; + +/** + * Lower values look more like a sharp, unshaded image. + * Higher values look more like an LCD display with subpixels. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelBlendAmount; + +/** + * Lower values make subpixels darker. + * Higher values make them lighter and over-bright. + * A value of 1 represents a normal, baseline gamma value. + * You'll normally want this to be somewhere around 1. + */ +uniform float SubpixelGamma; + +/** + * Higher values allow subpixels to be more blended-together + * and brighter. + * Lower values keep subpixel colors more separated. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelColorBleed; + +/** + * Determines the distance between subpixels. + * Lower values put the red, green, and blue subpixels + * within a single pixel closer together. + * Higher values put them farther apart. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelSpread; + +/** + * Determines the vertical offset of subpixels within + * a pixel. + * Lower values put the red, green, and blue subpixels + * within a single pixel higher up. + * Higher values put them further down. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelVerticalOffset; + +/** + * Lower values make the subpixels horizontally thinner, + * and higher values make them thicker. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelLightWidth; + +/** + * Lower values make the subpixels vertically taller, + * and higher values make them shorter. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelLightHeight; + +/** + * Lower values make the subpixels sharper and more + * individually distinct. + * Higher values add an increasingly intense glowing + * effect around each subpixel. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelLightGlow; + +/** + * Scale the size of pixels up or down. + * Useful for looking at larger than 8x8 subpixel sizes. + * You'll normally want this number to be exactly 1, + * meaning that every group of 3 subpixels corresponds + * to one pixel in the display. + */ +uniform float SubpixelScale; + +/** + * GBC subpixels are roughly rectangular shaped, but + * with a rectangular gap in the lower-right corner. + * Lower values make the lower-right gap in each GBC + * subpixel less distinct. A value of 0 results in no + * gap being shown at all. + * Higher values make the gap more distinct. + * You'll normally want this to be a number from 0 to 1. + */ +uniform float SubpixelTabHeight; + +/** + * The following three uniforms decide the base colors + * of each of the subpixels. + * + * Default subpixel colors are based on this resource: + * https://gbcc.dev/technology/ + * R: #FF7145 (1.00, 0.44, 0.27) + * G: #C1D650 (0.75, 0.84, 0.31) + * B: #3BCEFF (0.23, 0.81, 1.00) + */ +uniform vec3 SubpixelColorRed; // vec3(1.00, 0.38, 0.22); +uniform vec3 SubpixelColorGreen; // vec3(0.60, 0.88, 0.30); +uniform vec3 SubpixelColorBlue; // vec3(0.23, 0.65, 1.00); + +/** + * Helper to get luminosity of an RGB color. + * Used with HCL color space related code. + */ +float getColorLumosity(in vec3 rgb) { + return ( + (rgb.r * (5.0 / 16.0)) + + (rgb.g * (9.0 / 16.0)) + + (rgb.b * (2.0 / 16.0)) + ); +} + +/** + * Helper to convert RGB color to HCL. (Hue, Chroma, Luma) + */ +vec3 convertRgbToHcl(in vec3 rgb) { + float xMin = min(rgb.r, min(rgb.g, rgb.b)); + float xMax = max(rgb.r, max(rgb.g, rgb.b)); + float c = xMax - xMin; + float l = getColorLumosity(rgb); + float h = mod(( + c == 0 ? 0.0 : + xMax == rgb.r ? ((rgb.g - rgb.b) / c) : + xMax == rgb.g ? ((rgb.b - rgb.r) / c) + 2.0 : + xMax == rgb.b ? ((rgb.r - rgb.g) / c) + 4.0 : + 0.0 + ), 6.0); + return vec3(h, c, l); +} + +/** + * Helper to convert HCL color to RGB. (Hue, Chroma, Luma) + */ +vec3 convertHclToRgb(in vec3 hcl) { + vec3 rgb; + float h = mod(hcl.x, 6.0); + float c = hcl.y; + float l = hcl.z; + float x = c * (1.0 - abs(mod(h, 2.0) - 1.0)); + if(h <= 1.0) { + rgb = vec3(c, x, 0.0); + } + else if(h <= 2.0) { + rgb = vec3(x, c, 0.0); + } + else if(h <= 3.0) { + rgb = vec3(0.0, c, x); + } + else if(h <= 4.0) { + rgb = vec3(0.0, x, c); + } + else if(h <= 5.0) { + rgb = vec3(x, 0.0, c); + } + else { + rgb = vec3(c, 0.0, x); + } + float lRgb = getColorLumosity(rgb); + float m = l - lRgb; + return clamp(vec3(m, m, m) + rgb, 0.0, 1.0); +} + +/** + * Helper to check if a point is contained within + * a rectangular area. + */ +bool getPointInRect( + vec2 point, + vec2 rectTopLeft, + vec2 rectBottomRight +) { + return ( + point.x >= rectTopLeft.x && + point.y >= rectTopLeft.y && + point.x <= rectBottomRight.x && + point.y <= rectBottomRight.y + ); +} + +/** + * Helper to get the nearest offset vector from a + * point to a line segment. + * (The length of this offset vector is the nearest + * distance from the point to the line segment.) + * Thank you to https://stackoverflow.com/a/1501725 + */ +vec2 getPointLineDistance( + vec2 point, + vec2 line0, + vec2 line1 +) { + vec2 lineDelta = line0 - line1; + float lineLengthSq = dot(lineDelta, lineDelta); + if(lineLengthSq <= 0) { + return line0 - point; + } + float t = ( + dot(point - line0, line1 - line0) / lineLengthSq + ); + vec2 projection = ( + line0 + clamp(t, 0.0, 1.0) * (line1 - line0) + ); + return projection - point; +} + +/** + * Helper to get the nearest offset vector from a + * point to a rectangle. + * Returns (0, 0) for points within the rectangle. + */ +vec2 getPointRectDistance( + vec2 point, + vec2 rectTopLeft, + vec2 rectBottomRight +) { + if(getPointInRect(point, rectTopLeft, rectBottomRight)) { + return vec2(0.0, 0.0); + } + vec2 rectTopRight = vec2(rectBottomRight.x, rectTopLeft.y); + vec2 rectBottomLeft = vec2(rectTopLeft.x, rectBottomRight.y); + vec2 v0 = getPointLineDistance(point, rectTopLeft, rectTopRight); + vec2 v1 = getPointLineDistance(point, rectBottomLeft, rectBottomRight); + vec2 v2 = getPointLineDistance(point, rectTopLeft, rectBottomLeft); + vec2 v3 = getPointLineDistance(point, rectTopRight, rectBottomRight); + float v0LengthSq = dot(v0, v0); + float v1LengthSq = dot(v1, v1); + float v2LengthSq = dot(v2, v2); + float v3LengthSq = dot(v3, v3); + float minLengthSq = min( + min(v0LengthSq, v1LengthSq), + min(v2LengthSq, v3LengthSq) + ); + if(minLengthSq == v0LengthSq) { + return v0; + } + else if(minLengthSq == v1LengthSq) { + return v1; + } + else if(minLengthSq == v2LengthSq) { + return v2; + } + else { + return v3; + } +} + +/** + * Helper to get the nearest offset vector from a + * point to a subpixel. + * GBC subpixels are roughly rectangular in shape, + * but have a rectangular gap in their bottom-left + * corner. + * Returns (0, 0) for points within the subpixel. + */ +vec2 getPointSubpixelDistance( + vec2 point, + vec2 subpixelCenter, + vec2 subpixelSizeHalf +) { + float rectLeft = subpixelCenter.x - subpixelSizeHalf.x; + float rectRight = subpixelCenter.x + subpixelSizeHalf.x; + float rectTop = subpixelCenter.y - subpixelSizeHalf.y; + float rectBottom = subpixelCenter.y + subpixelSizeHalf.y; + vec2 offsetLeft = getPointRectDistance( + point, + vec2(rectLeft, rectTop + SubpixelTabHeight), + vec2(subpixelCenter.x, rectBottom) + ); + vec2 offsetRight = getPointRectDistance( + point, + vec2(subpixelCenter.x, rectTop), + vec2(rectRight, rectBottom) + ); + float offsetLeftLengthSq = dot(offsetLeft, offsetLeft); + float offsetRightLengthSq = dot(offsetRight, offsetRight); + if(offsetLeftLengthSq <= offsetRightLengthSq) { + return offsetLeft; + } + else { + return offsetRight; + } +} + +/** + * Helper to get the intensity of light from a + * subpixel. + * The pixelPosition argument represents a + * fragment's position within a pixel. + * Spread represents the subpixel's horizontal + * position within the pixel. + */ +float getSubpixelIntensity( + vec2 pixelPosition, + float spread +) { + vec2 subpixelCenter = vec2( + 0.5 + (spread * SubpixelSpread), + 1.0 - SubpixelVerticalOffset + ); + vec2 subpixelSizeHalf = 0.5 * vec2( + SubpixelLightWidth, + SubpixelLightHeight + ); + vec2 offset = getPointSubpixelDistance( + pixelPosition, + subpixelCenter, + subpixelSizeHalf + ); + if(SubpixelLightGlow <= 0) { + return dot(offset, offset) <= 0.0 ? 1.0 : 0.0; + } + else { + float dist = length(offset); + float glow = max(0.0, + 1.0 - (dist / SubpixelLightGlow) + ); + return glow; + } +} + +/** + * Helper to apply SubpixelColorBleed to the intensity + * value computed for a fragment and subpixel. + * Subpixel color bleed allows subpixel colors to be + * more strongly coerced to more accurately represent + * the underlying pixel color. + */ +float applySubpixelBleed( + float subpixelIntensity, + float colorSourceChannel +) { + return subpixelIntensity * ( + SubpixelColorBleed + + ((1.0 - SubpixelColorBleed) * colorSourceChannel) + ); +} + +void main() { + // Get base color of the pixel, adjust based on + // contrast and luminosity settings. + vec3 colorSource = texture2D(tex, texCoord).rgb; + vec3 colorSourceHcl = convertRgbToHcl(colorSource); + vec3 colorSourceAdjusted = convertHclToRgb(vec3( + colorSourceHcl.x, + colorSourceHcl.y * SourceContrast, + colorSourceHcl.z * SourceLuminosity + )); + // Determine how much each subpixel's light should + // affect this fragment. + vec2 pixelPosition = ( + mod(texCoord * texSize * SubpixelScale, 1.0) + ); + float subpixelIntensityRed = applySubpixelBleed( + getSubpixelIntensity(pixelPosition, -1.0), + colorSourceAdjusted.r + ); + float subpixelIntensityGreen = applySubpixelBleed( + getSubpixelIntensity(pixelPosition, +0.0), + colorSourceAdjusted.g + ); + float subpixelIntensityBlue = applySubpixelBleed( + getSubpixelIntensity(pixelPosition, +1.0), + colorSourceAdjusted.b + ); + vec3 subpixelLightColor = SubpixelGamma * ( + (subpixelIntensityRed * SubpixelColorRed) + + (subpixelIntensityGreen * SubpixelColorGreen) + + (subpixelIntensityBlue * SubpixelColorBlue) + ); + // Compute final color + vec3 colorResult = clamp( + subpixelLightColor * colorSourceAdjusted, 0.0, 1.0 + ); + vec3 colorResultBlended = ( + ((1.0 - SubpixelBlendAmount) * colorSourceAdjusted) + + (SubpixelBlendAmount * colorResult) + ); + colorResultBlended = BaseColor + ( + (colorResultBlended * (vec3(1.0, 1.0, 1.0) - BaseColor)) + ); + gl_FragColor = vec4( + colorResultBlended, + 1.0 + ); +} diff --git a/res/shaders/gbc-lcd.shader/license.txt b/res/shaders/gbc-lcd.shader/license.txt new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/res/shaders/gbc-lcd.shader/license.txt @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/res/shaders/gbc-lcd.shader/manifest.ini b/res/shaders/gbc-lcd.shader/manifest.ini new file mode 100644 index 000000000..3af7e9e2f --- /dev/null +++ b/res/shaders/gbc-lcd.shader/manifest.ini @@ -0,0 +1,129 @@ +[shader] +name=gbc-lcd +author=Sophie Kirschner +description=Imitates the GameBoy Color LCD screen subpixel arrangement, with an optional backlight effect. +passes=2 + +[pass.0] +integerScaling=1 +fragmentShader=gbc-lcd.fs +blend=1 + +[pass.1] +fragmentShader=gbc-lcd-light.fs + +[pass.0.uniform.BaseColor] +type=float3 +default[0]=0.130 +default[1]=0.128 +default[2]=0.101 +readableName=Screen base color + +[pass.0.uniform.SubpixelColorRed] +type=float3 +default[0]=1.00 +default[1]=0.38 +default[2]=0.22 +readableName=Red subpixel color + +[pass.0.uniform.SubpixelColorGreen] +type=float3 +default[0]=0.60 +default[1]=0.88 +default[2]=0.30 +readableName=Green subpixel color + +[pass.0.uniform.SubpixelColorBlue] +type=float3 +default[0]=0.23 +default[1]=0.65 +default[2]=1.00 +readableName=Blue subpixel color + +[pass.0.uniform.SourceContrast] +type=float +default=0.85 +readableName=Screen contrast + +[pass.0.uniform.SourceLuminosity] +type=float +default=0.88 +readableName=Screen luminosity + +[pass.0.uniform.SubpixelBlendAmount] +type=float +default=1.0 +readableName=Subpixel effect amount + +[pass.0.uniform.SubpixelColorBleed] +type=float +default=0.31 +readableName=Subpixel color bleeding + +[pass.0.uniform.SubpixelSpread] +type=float +default=0.333 +readableName=Subpixel spread X + +[pass.0.uniform.SubpixelVerticalOffset] +type=float +default=0.48 +readableName=Subpixel offset Y + +[pass.0.uniform.SubpixelGamma] +type=float +default=1.040 +readableName=Subpixel brightness + +[pass.0.uniform.SubpixelLightWidth] +type=float +default=0.220 +readableName=Subpixel width + +[pass.0.uniform.SubpixelLightHeight] +type=float +default=0.850 +readableName=Subpixel height + +[pass.0.uniform.SubpixelLightGlow] +type=float +default=0.195 +readableName=Subpixel glow size + +[pass.0.uniform.SubpixelTabHeight] +type=float +default=0.175 +readableName=Subpixel tab shaping + +[pass.0.uniform.SubpixelScale] +type=float +default=1.0 +readableName=Subpixel scale + +[pass.1.uniform.LightColor] +type=float3 +default[0]=1.000 +default[1]=0.968 +default[2]=0.882 +readableName=Backlight color + +[pass.1.uniform.LightIntensity] +type=float +default=0.06 +readableName=Backlight intensity + +[pass.1.uniform.LightSoftness] +type=float +default=0.67 +readableName=Backlight softness + +[pass.1.uniform.ReflectionDistance] +type=float2 +default[0]=0 +default[1]=0.025 +readableName=Internal reflection distance + +[pass.1.uniform.ReflectionBrightness] +type=float +default=0.032 +readableName=Internal reflection brightness diff --git a/res/shaders/hq2x.shader/hq2x.fs b/res/shaders/hq2x.shader/hq2x.fs new file mode 100644 index 000000000..97019bd3c --- /dev/null +++ b/res/shaders/hq2x.shader/hq2x.fs @@ -0,0 +1,143 @@ +/* MIT License +* +* Copyright (c) 2015-2023 Lior Halphon +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +/* Based on this (really good) article: http://blog.pkh.me/p/19-butchering-hqx-scaling-filters.html */ + +/* The colorspace used by the HQnx filters is not really YUV, despite the algorithm description claims it is. It is + also not normalized. Therefore, we shall call the colorspace used by HQnx "HQ Colorspace" to avoid confusion. */ +varying vec2 texCoord; +uniform sampler2D tex; +uniform vec2 texSize; + +vec3 rgb_to_hq_colospace(vec4 rgb) +{ + return vec3( 0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b, + 0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b, + -0.125 * rgb.r + 0.250 * rgb.g - 0.125 * rgb.b); +} + +bool is_different(vec4 a, vec4 b) +{ + vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b)); + return diff.x > 0.018 || diff.y > 0.002 || diff.z > 0.005; +} + +#define P(m, r) ((pattern & (m)) == (r)) + +vec4 interp_2px(vec4 c1, float w1, vec4 c2, float w2) +{ + return (c1 * w1 + c2 * w2) / (w1 + w2); +} + +vec4 interp_3px(vec4 c1, float w1, vec4 c2, float w2, vec4 c3, float w3) +{ + return (c1 * w1 + c2 * w2 + c3 * w3) / (w1 + w2 + w3); +} + +vec4 scale(sampler2D image, vec2 position, vec2 input_resolution) +{ + // o = offset, the width of a pixel + vec2 o = vec2(1, 1) / input_resolution; + + /* We always calculate the top left pixel. If we need a different pixel, we flip the image */ + + // p = the position within a pixel [0...1] + vec2 p = fract(position * input_resolution); + + if (p.x > 0.5) o.x = -o.x; + if (p.y > 0.5) o.y = -o.y; + + vec4 w0 = texture2D(image, position + vec2( -o.x, -o.y)); + vec4 w1 = texture2D(image, position + vec2( 0, -o.y)); + vec4 w2 = texture2D(image, position + vec2( o.x, -o.y)); + vec4 w3 = texture2D(image, position + vec2( -o.x, 0)); + vec4 w4 = texture2D(image, position + vec2( 0, 0)); + vec4 w5 = texture2D(image, position + vec2( o.x, 0)); + vec4 w6 = texture2D(image, position + vec2( -o.x, o.y)); + vec4 w7 = texture2D(image, position + vec2( 0, o.y)); + vec4 w8 = texture2D(image, position + vec2( o.x, o.y)); + + int pattern = 0; + if (is_different(w0, w4)) pattern |= 1; + if (is_different(w1, w4)) pattern |= 2; + if (is_different(w2, w4)) pattern |= 4; + if (is_different(w3, w4)) pattern |= 8; + if (is_different(w5, w4)) pattern |= 16; + if (is_different(w6, w4)) pattern |= 32; + if (is_different(w7, w4)) pattern |= 64; + if (is_different(w8, w4)) pattern |= 128; + + if ((P(0xBF,0x37) || P(0xDB,0x13)) && is_different(w1, w5)) { + return interp_2px(w4, 3.0, w3, 1.0); + } + if ((P(0xDB,0x49) || P(0xEF,0x6D)) && is_different(w7, w3)) { + return interp_2px(w4, 3.0, w1, 1.0); + } + if ((P(0x0B,0x0B) || P(0xFE,0x4A) || P(0xFE,0x1A)) && is_different(w3, w1)) { + return w4; + } + if ((P(0x6F,0x2A) || P(0x5B,0x0A) || P(0xBF,0x3A) || P(0xDF,0x5A) || + P(0x9F,0x8A) || P(0xCF,0x8A) || P(0xEF,0x4E) || P(0x3F,0x0E) || + P(0xFB,0x5A) || P(0xBB,0x8A) || P(0x7F,0x5A) || P(0xAF,0x8A) || + P(0xEB,0x8A)) && is_different(w3, w1)) { + return interp_2px(w4, 3.0, w0, 1.0); + } + if (P(0x0B,0x08)) { + return interp_3px(w4, 2.0, w0, 1.0, w1, 1.0); + } + if (P(0x0B,0x02)) { + return interp_3px(w4, 2.0, w0, 1.0, w3, 1.0); + } + if (P(0x2F,0x2F)) { + return interp_3px(w4, 4.0, w3, 1.0, w1, 1.0); + } + if (P(0xBF,0x37) || P(0xDB,0x13)) { + return interp_3px(w4, 5.0, w1, 2.0, w3, 1.0); + } + if (P(0xDB,0x49) || P(0xEF,0x6D)) { + return interp_3px(w4, 5.0, w3, 2.0, w1, 1.0); + } + if (P(0x1B,0x03) || P(0x4F,0x43) || P(0x8B,0x83) || P(0x6B,0x43)) { + return interp_2px(w4, 3.0, w3, 1.0); + } + if (P(0x4B,0x09) || P(0x8B,0x89) || P(0x1F,0x19) || P(0x3B,0x19)) { + return interp_2px(w4, 3.0, w1, 1.0); + } + if (P(0x7E,0x2A) || P(0xEF,0xAB) || P(0xBF,0x8F) || P(0x7E,0x0E)) { + return interp_3px(w4, 2.0, w3, 3.0, w1, 3.0); + } + if (P(0xFB,0x6A) || P(0x6F,0x6E) || P(0x3F,0x3E) || P(0xFB,0xFA) || + P(0xDF,0xDE) || P(0xDF,0x1E)) { + return interp_2px(w4, 3.0, w0, 1.0); + } + if (P(0x0A,0x00) || P(0x4F,0x4B) || P(0x9F,0x1B) || P(0x2F,0x0B) || + P(0xBE,0x0A) || P(0xEE,0x0A) || P(0x7E,0x0A) || P(0xEB,0x4B) || + P(0x3B,0x1B)) { + return interp_3px(w4, 2.0, w3, 1.0, w1, 1.0); + } + + return interp_3px(w4, 6.0, w3, 1.0, w1, 1.0); +} + +void main() { + gl_FragColor = scale(tex, texCoord, texSize); +} diff --git a/res/shaders/hq2x.shader/manifest.ini b/res/shaders/hq2x.shader/manifest.ini new file mode 100644 index 000000000..c0ab0ef8a --- /dev/null +++ b/res/shaders/hq2x.shader/manifest.ini @@ -0,0 +1,11 @@ +[shader] +name=hq2x +author=Lior Halphon +description="High Quality" 2x scaling +passes=1 + +[pass.0] +fragmentShader=hq2x.fs +blend=0 +width=-2 +height=-2 diff --git a/res/shaders/omniscale.shader/manifest.ini b/res/shaders/omniscale.shader/manifest.ini new file mode 100644 index 000000000..a98e34ce2 --- /dev/null +++ b/res/shaders/omniscale.shader/manifest.ini @@ -0,0 +1,9 @@ +[shader] +name=OmniScale +author=Lior Halphon +description=Resolution-indepedent scaler inspired by the hqx family scalers +passes=1 + +[pass.0] +fragmentShader=omniscale.fs +blend=0 diff --git a/res/shaders/omniscale.shader/omniscale.fs b/res/shaders/omniscale.shader/omniscale.fs new file mode 100644 index 000000000..d6b71475b --- /dev/null +++ b/res/shaders/omniscale.shader/omniscale.fs @@ -0,0 +1,292 @@ +/* MIT License +* +* Copyright (c) 2015-2023 Lior Halphon +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +/* OmniScale is derived from the pattern based design of HQnx, but with the following general differences: + - The actual output calculating was completely redesigned as resolution independent graphic generator. This allows + scaling to any factor. + - HQnx approximations that were good enough for a 2x/3x/4x factor were refined, creating smoother gradients. + - "Quarters" can be interpolated in more ways than in the HQnx filters + - If a pattern does not provide enough information to determine the suitable scaling interpolation, up to 16 pixels + per quarter are sampled (in contrast to the usual 9) in order to determine the best interpolation. + */ +varying vec2 texCoord; +uniform sampler2D tex; +uniform vec2 texSize; +uniform vec2 outputSize; + +/* We use the same colorspace as the HQ algorithms. */ +vec3 rgb_to_hq_colospace(vec4 rgb) +{ + return vec3( 0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b, + 0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b, + -0.125 * rgb.r + 0.250 * rgb.g - 0.125 * rgb.b); +} + + +bool is_different(vec4 a, vec4 b) +{ + vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b)); + return diff.x > 0.018 || diff.y > 0.002 || diff.z > 0.005; +} + +#define P(m, r) ((pattern & (m)) == (r)) + +vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution) +{ + // o = offset, the width of a pixel + vec2 o = vec2(1, 1) / input_resolution; + + /* We always calculate the top left quarter. If we need a different quarter, we flip our co-ordinates */ + + // p = the position within a pixel [0...1] + vec2 p = fract(position * input_resolution); + + if (p.x > 0.5) { + o.x = -o.x; + p.x = 1.0 - p.x; + } + if (p.y > 0.5) { + o.y = -o.y; + p.y = 1.0 - p.y; + } + + vec4 w0 = texture2D(image, position + vec2( -o.x, -o.y)); + vec4 w1 = texture2D(image, position + vec2( 0, -o.y)); + vec4 w2 = texture2D(image, position + vec2( o.x, -o.y)); + vec4 w3 = texture2D(image, position + vec2( -o.x, 0)); + vec4 w4 = texture2D(image, position + vec2( 0, 0)); + vec4 w5 = texture2D(image, position + vec2( o.x, 0)); + vec4 w6 = texture2D(image, position + vec2( -o.x, o.y)); + vec4 w7 = texture2D(image, position + vec2( 0, o.y)); + vec4 w8 = texture2D(image, position + vec2( o.x, o.y)); + + int pattern = 0; + if (is_different(w0, w4)) pattern |= 1 << 0; + if (is_different(w1, w4)) pattern |= 1 << 1; + if (is_different(w2, w4)) pattern |= 1 << 2; + if (is_different(w3, w4)) pattern |= 1 << 3; + if (is_different(w5, w4)) pattern |= 1 << 4; + if (is_different(w6, w4)) pattern |= 1 << 5; + if (is_different(w7, w4)) pattern |= 1 << 6; + if (is_different(w8, w4)) pattern |= 1 << 7; + + if ((P(0xBF,0x37) || P(0xDB,0x13)) && is_different(w1, w5)) { + return mix(w4, w3, 0.5 - p.x); + } + if ((P(0xDB,0x49) || P(0xEF,0x6D)) && is_different(w7, w3)) { + return mix(w4, w1, 0.5 - p.y); + } + if ((P(0x0B,0x0B) || P(0xFE,0x4A) || P(0xFE,0x1A)) && is_different(w3, w1)) { + return w4; + } + if ((P(0x6F,0x2A) || P(0x5B,0x0A) || P(0xBF,0x3A) || P(0xDF,0x5A) || + P(0x9F,0x8A) || P(0xCF,0x8A) || P(0xEF,0x4E) || P(0x3F,0x0E) || + P(0xFB,0x5A) || P(0xBB,0x8A) || P(0x7F,0x5A) || P(0xAF,0x8A) || + P(0xEB,0x8A)) && is_different(w3, w1)) { + return mix(w4, mix(w4, w0, 0.5 - p.x), 0.5 - p.y); + } + if (P(0x0B,0x08)) { + return mix(mix(w0 * 0.375 + w1 * 0.25 + w4 * 0.375, w4 * 0.5 + w1 * 0.5, p.x * 2.0), w4, p.y * 2.0); + } + if (P(0x0B,0x02)) { + return mix(mix(w0 * 0.375 + w3 * 0.25 + w4 * 0.375, w4 * 0.5 + w3 * 0.5, p.y * 2.0), w4, p.x * 2.0); + } + if (P(0x2F,0x2F)) { + float dist = length(p - vec2(0.5)); + float pixel_size = length(1.0 / (output_resolution / input_resolution)); + if (dist < 0.5 - pixel_size / 2) { + return w4; + } + vec4 r; + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0); + } + + if (dist > 0.5 + pixel_size / 2) { + return r; + } + return mix(w4, r, (dist - 0.5 + pixel_size / 2) / pixel_size); + } + if (P(0xBF,0x37) || P(0xDB,0x13)) { + float dist = p.x - 2.0 * p.y; + float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0); + if (dist > pixel_size / 2) { + return w1; + } + vec4 r = mix(w3, w4, p.x + 0.5); + if (dist < -pixel_size / 2) { + return r; + } + return mix(r, w1, (dist + pixel_size / 2) / pixel_size); + } + if (P(0xDB,0x49) || P(0xEF,0x6D)) { + float dist = p.y - 2.0 * p.x; + float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0); + if (p.y - 2.0 * p.x > pixel_size / 2) { + return w3; + } + vec4 r = mix(w1, w4, p.x + 0.5); + if (dist < -pixel_size / 2) { + return r; + } + return mix(r, w3, (dist + pixel_size / 2) / pixel_size); + } + if (P(0xBF,0x8F) || P(0x7E,0x0E)) { + float dist = p.x + 2.0 * p.y; + float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0); + + if (dist > 1.0 + pixel_size / 2) { + return w4; + } + + vec4 r; + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0); + } + + if (dist < 1.0 - pixel_size / 2) { + return r; + } + + return mix(r, w4, (dist + pixel_size / 2 - 1.0) / pixel_size); + } + + if (P(0x7E,0x2A) || P(0xEF,0xAB)) { + float dist = p.y + 2.0 * p.x; + float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0); + + if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2) { + return w4; + } + + vec4 r; + + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0); + } + + if (dist < 1.0 - pixel_size / 2) { + return r; + } + + return mix(r, w4, (dist + pixel_size / 2 - 1.0) / pixel_size); + } + + if (P(0x1B,0x03) || P(0x4F,0x43) || P(0x8B,0x83) || P(0x6B,0x43)) { + return mix(w4, w3, 0.5 - p.x); + } + + if (P(0x4B,0x09) || P(0x8B,0x89) || P(0x1F,0x19) || P(0x3B,0x19)) { + return mix(w4, w1, 0.5 - p.y); + } + + if (P(0xFB,0x6A) || P(0x6F,0x6E) || P(0x3F,0x3E) || P(0xFB,0xFA) || + P(0xDF,0xDE) || P(0xDF,0x1E)) { + return mix(w4, w0, (1.0 - p.x - p.y) / 2.0); + } + + if (P(0x4F,0x4B) || P(0x9F,0x1B) || P(0x2F,0x0B) || + P(0xBE,0x0A) || P(0xEE,0x0A) || P(0x7E,0x0A) || P(0xEB,0x4B) || + P(0x3B,0x1B)) { + float dist = p.x + p.y; + float pixel_size = length(1.0 / (output_resolution / input_resolution)); + + if (dist > 0.5 + pixel_size / 2) { + return w4; + } + + vec4 r; + if (is_different(w0, w1) || is_different(w0, w3)) { + r = mix(w1, w3, p.y - p.x + 0.5); + } + else { + r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0); + } + + if (dist < 0.5 - pixel_size / 2) { + return r; + } + + return mix(r, w4, (dist + pixel_size / 2 - 0.5) / pixel_size); + } + + if (P(0x0B,0x01)) { + return mix(mix(w4, w3, 0.5 - p.x), mix(w1, (w1 + w3) / 2.0, 0.5 - p.x), 0.5 - p.y); + } + + if (P(0x0B,0x00)) { + return mix(mix(w4, w3, 0.5 - p.x), mix(w1, w0, 0.5 - p.x), 0.5 - p.y); + } + + float dist = p.x + p.y; + float pixel_size = length(1.0 / (output_resolution / input_resolution)); + + if (dist > 0.5 + pixel_size / 2) { + return w4; + } + + /* We need more samples to "solve" this diagonal */ + vec4 x0 = texture2D(image, position + vec2( -o.x * 2.0, -o.y * 2.0)); + vec4 x1 = texture2D(image, position + vec2( -o.x , -o.y * 2.0)); + vec4 x2 = texture2D(image, position + vec2( 0.0 , -o.y * 2.0)); + vec4 x3 = texture2D(image, position + vec2( o.x , -o.y * 2.0)); + vec4 x4 = texture2D(image, position + vec2( -o.x * 2.0, -o.y )); + vec4 x5 = texture2D(image, position + vec2( -o.x * 2.0, 0.0 )); + vec4 x6 = texture2D(image, position + vec2( -o.x * 2.0, o.y )); + + if (is_different(x0, w4)) pattern |= 1 << 8; + if (is_different(x1, w4)) pattern |= 1 << 9; + if (is_different(x2, w4)) pattern |= 1 << 10; + if (is_different(x3, w4)) pattern |= 1 << 11; + if (is_different(x4, w4)) pattern |= 1 << 12; + if (is_different(x5, w4)) pattern |= 1 << 13; + if (is_different(x6, w4)) pattern |= 1 << 14; + + int diagonal_bias = -7; + while (pattern != 0) { + diagonal_bias += pattern & 1; + pattern >>= 1; + } + + if (diagonal_bias <= 0) { + vec4 r = mix(w1, w3, p.y - p.x + 0.5); + if (dist < 0.5 - pixel_size / 2) { + return r; + } + return mix(r, w4, (dist + pixel_size / 2 - 0.5) / pixel_size); + } + + return w4; +} + +void main() { + gl_FragColor = scale(tex, texCoord, texSize, outputSize); +} diff --git a/src/arm/arm.c b/src/arm/arm.c index 37dfe726c..cb93136aa 100644 --- a/src/arm/arm.c +++ b/src/arm/arm.c @@ -234,6 +234,9 @@ void ARMRun(struct ARMCore* cpu) { } else { ARMStep(cpu); } + while (cpu->cycles >= cpu->nextEvent) { + cpu->irqh.processEvents(cpu); + } } void ARMRunLoop(struct ARMCore* cpu) { diff --git a/src/arm/debugger/cli-debugger.c b/src/arm/debugger/cli-debugger.c index 4df448151..60caa7a21 100644 --- a/src/arm/debugger/cli-debugger.c +++ b/src/arm/debugger/cli-debugger.c @@ -52,7 +52,7 @@ static inline void _printPSR(struct CLIDebuggerBackend* be, union PSR psr) { } static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) { - struct ARMCore* cpu = debugger->p->d.core->cpu; + struct ARMCore* cpu = debugger->p->d.p->core->cpu; _disassembleMode(debugger->p, dv, cpu->executionMode); } @@ -65,7 +65,7 @@ static void _disassembleThumb(struct CLIDebugger* debugger, struct CLIDebugVecto } static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector* dv, enum ExecutionMode mode) { - struct ARMCore* cpu = debugger->d.core->cpu; + struct ARMCore* cpu = debugger->d.p->core->cpu; uint32_t address; int size; int wordSize; @@ -98,7 +98,7 @@ static void _disassembleMode(struct CLIDebugger* debugger, struct CLIDebugVector static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address, enum ExecutionMode mode) { struct CLIDebuggerBackend* be = debugger->backend; - struct mCore* core = debugger->d.core; + struct mCore* core = debugger->d.p->core; char disassembly[64]; struct ARMInstructionInfo info; address &= ~(WORD_SIZE_THUMB - 1); @@ -130,7 +130,7 @@ static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address static void _printStatus(struct CLIDebuggerSystem* debugger) { struct CLIDebuggerBackend* be = debugger->p->backend; - struct ARMCore* cpu = debugger->p->d.core->cpu; + struct ARMCore* cpu = debugger->p->d.p->core->cpu; int r; for (r = 0; r < 16; r += 4) { be->printf(be, "%sr%i: %08X %sr%i: %08X %sr%i: %08X %sr%i: %08X\n", @@ -141,7 +141,7 @@ static void _printStatus(struct CLIDebuggerSystem* debugger) { } be->printf(be, "cpsr: "); _printPSR(be, cpu->cpsr); - be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing)); + be->printf(be, "Cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.p->core->timing)); int instructionLength; enum ExecutionMode mode = cpu->cpsr.t; if (mode == MODE_ARM) { @@ -159,7 +159,7 @@ static void _setBreakpointARM(struct CLIDebugger* debugger, struct CLIDebugVecto return; } uint32_t address = dv->intValue; - ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_ARM); + ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.p->platform, &debugger->d, address, MODE_ARM); if (id > 0) { debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id); } @@ -172,7 +172,7 @@ static void _setBreakpointThumb(struct CLIDebugger* debugger, struct CLIDebugVec return; } uint32_t address = dv->intValue; - ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.platform, address, MODE_THUMB); + ssize_t id = ARMDebuggerSetSoftwareBreakpoint(debugger->d.p->platform, &debugger->d, address, MODE_THUMB); if (id > 0) { debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id); } diff --git a/src/arm/debugger/debugger.c b/src/arm/debugger/debugger.c index afc1e0c49..8fe474258 100644 --- a/src/arm/debugger/debugger.c +++ b/src/arm/debugger/debugger.c @@ -187,16 +187,18 @@ static struct ARMDebugBreakpoint* _lookupBreakpoint(struct ARMDebugBreakpointLis return 0; } -static void _destroyBreakpoint(struct ARMDebugBreakpoint* breakpoint) { +static void _destroyBreakpoint(struct mDebugger* debugger, struct ARMDebugBreakpoint* breakpoint) { if (breakpoint->d.condition) { parseFree(breakpoint->d.condition); } + TableRemove(&debugger->pointOwner, breakpoint->d.id); } -static void _destroyWatchpoint(struct mWatchpoint* watchpoint) { +static void _destroyWatchpoint(struct mDebugger* debugger, struct mWatchpoint* watchpoint) { if (watchpoint->condition) { parseFree(watchpoint->condition); } + TableRemove(&debugger->pointOwner, watchpoint->id); } static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { @@ -220,7 +222,8 @@ static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { struct mDebuggerEntryInfo info = { .address = breakpoint->d.address, .type.bp.breakType = BREAKPOINT_HARDWARE, - .pointId = breakpoint->d.id + .pointId = breakpoint->d.id, + .target = TableLookup(&d->p->pointOwner, breakpoint->d.id) }; mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info); } @@ -230,19 +233,20 @@ static void ARMDebuggerDeinit(struct mDebuggerPlatform* platform); static void ARMDebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info); -static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*); +static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform*, struct mDebuggerModule* owner, const struct mBreakpoint*); static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id); -static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*); -static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*); -static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*); +static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform*, struct mDebuggerModule* owner, struct mBreakpointList*); +static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform*, struct mDebuggerModule* owner, const struct mWatchpoint*); +static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform*, struct mDebuggerModule* owner, struct mWatchpointList*); static void ARMDebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform*); static void ARMDebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); static void ARMDebuggerFormatRegisters(struct ARMRegisterFile* regs, char* out, size_t* length); static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out, size_t* length); -static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform*); -static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform*, uint32_t); +static enum mStackTraceMode ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform*); +static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform*, enum mStackTraceMode); static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d); +static void ARMDebuggerNextInstructionInfo(struct mDebuggerPlatform* d, struct mDebuggerInstructionInfo*); struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { struct mDebuggerPlatform* platform = (struct mDebuggerPlatform*) malloc(sizeof(struct ARMDebugger)); @@ -260,6 +264,7 @@ struct mDebuggerPlatform* ARMDebuggerPlatformCreate(void) { platform->getStackTraceMode = ARMDebuggerGetStackTraceMode; platform->setStackTraceMode = ARMDebuggerSetStackTraceMode; platform->updateStackTrace = ARMDebuggerUpdateStackTrace; + platform->nextInstructionInfo = ARMDebuggerNextInstructionInfo; return platform; } @@ -291,12 +296,12 @@ void ARMDebuggerDeinit(struct mDebuggerPlatform* platform) { size_t i; for (i = 0; i < ARMDebugBreakpointListSize(&debugger->breakpoints); ++i) { - _destroyBreakpoint(ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i)); + _destroyBreakpoint(debugger->d.p, ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i)); } ARMDebugBreakpointListDeinit(&debugger->breakpoints); for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { - _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i)); + _destroyWatchpoint(debugger->d.p, mWatchpointListGetPointer(&debugger->watchpoints, i)); } ARMDebugBreakpointListDeinit(&debugger->swBreakpoints); mWatchpointListDeinit(&debugger->watchpoints); @@ -323,12 +328,9 @@ static void ARMDebuggerEnter(struct mDebuggerPlatform* platform, enum mDebuggerE } } } - if (debugger->d.p->entered) { - debugger->d.p->entered(debugger->d.p, reason, info); - } } -ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t address, enum ExecutionMode mode) { +ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, uint32_t address, enum ExecutionMode mode) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; uint32_t opcode; if (!debugger->setSoftwareBreakpoint || !debugger->setSoftwareBreakpoint(debugger, address, mode, &opcode)) { @@ -345,11 +347,12 @@ ssize_t ARMDebuggerSetSoftwareBreakpoint(struct mDebuggerPlatform* d, uint32_t a breakpoint->d.type = BREAKPOINT_SOFTWARE; breakpoint->sw.opcode = opcode; breakpoint->sw.mode = mode; + TableInsert(&debugger->d.p->pointOwner, id, owner); return id; } -static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) { +static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, const struct mBreakpoint* info) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct ARMDebugBreakpoint* breakpoint = ARMDebugBreakpointListAppend(&debugger->breakpoints); ssize_t id = debugger->nextId; @@ -357,6 +360,7 @@ static ssize_t ARMDebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struc breakpoint->d = *info; breakpoint->d.address &= ~1; // Clear Thumb bit since it's not part of a valid address breakpoint->d.id = id; + TableInsert(&debugger->d.p->pointOwner, id, owner); if (info->type == BREAKPOINT_SOFTWARE) { // TODO abort(); @@ -371,7 +375,7 @@ static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) struct ARMDebugBreakpointList* breakpoints = &debugger->breakpoints; for (i = 0; i < ARMDebugBreakpointListSize(breakpoints); ++i) { if (ARMDebugBreakpointListGetPointer(breakpoints, i)->d.id == id) { - _destroyBreakpoint(ARMDebugBreakpointListGetPointer(breakpoints, i)); + _destroyBreakpoint(debugger->d.p, ARMDebugBreakpointListGetPointer(breakpoints, i)); ARMDebugBreakpointListShift(breakpoints, i, 1); return true; } @@ -391,7 +395,7 @@ static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) struct mWatchpointList* watchpoints = &debugger->watchpoints; for (i = 0; i < mWatchpointListSize(watchpoints); ++i) { if (mWatchpointListGetPointer(watchpoints, i)->id == id) { - _destroyWatchpoint(mWatchpointListGetPointer(watchpoints, i)); + _destroyWatchpoint(debugger->d.p, mWatchpointListGetPointer(watchpoints, i)); mWatchpointListShift(watchpoints, i, 1); if (!mWatchpointListSize(&debugger->watchpoints)) { ARMDebuggerRemoveMemoryShim(debugger); @@ -402,7 +406,7 @@ static bool ARMDebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) return false; } -static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) { +static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, struct mBreakpointList* list) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; mBreakpointListClear(list); size_t i, s; @@ -411,10 +415,20 @@ static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBrea struct ARMDebugBreakpoint* sw = NULL; if (i < ARMDebugBreakpointListSize(&debugger->breakpoints)) { hw = ARMDebugBreakpointListGetPointer(&debugger->breakpoints, i); + if (owner && TableLookup(&debugger->d.p->pointOwner, hw->d.id) != owner) { + hw = NULL; + } } if (s < ARMDebugBreakpointListSize(&debugger->swBreakpoints)) { sw = ARMDebugBreakpointListGetPointer(&debugger->swBreakpoints, s); + if (owner && TableLookup(&debugger->d.p->pointOwner, sw->d.id) != owner) { + sw = NULL; + } } + if (!hw && !sw) { + continue; + } + struct mBreakpoint* b = mBreakpointListAppend(list); if (hw && sw) { if (hw->d.id < sw->d.id) { @@ -430,8 +444,6 @@ static void ARMDebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBrea } else if (sw) { *b = sw->d; ++s; - } else { - abort(); // Should be unreachable } } } @@ -441,7 +453,7 @@ static bool ARMDebuggerHasBreakpoints(struct mDebuggerPlatform* d) { return ARMDebugBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints) || debugger->stackTraceMode != STACK_TRACE_DISABLED; } -static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) { +static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, const struct mWatchpoint* info) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; if (!mWatchpointListSize(&debugger->watchpoints)) { ARMDebuggerInstallMemoryShim(debugger); @@ -451,13 +463,25 @@ static ssize_t ARMDebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struc ++debugger->nextId; *watchpoint = *info; watchpoint->id = id; + TableInsert(&debugger->d.p->pointOwner, id, owner); return id; } -static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) { +static void ARMDebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, struct mWatchpointList* list) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; mWatchpointListClear(list); - mWatchpointListCopy(list, &debugger->watchpoints); + if (owner) { + size_t i; + for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { + struct mWatchpoint* point = mWatchpointListGetPointer(&debugger->watchpoints, i); + if (TableLookup(&debugger->d.p->pointOwner, point->id) != owner) { + continue; + } + memcpy(mWatchpointListAppend(list), point, sizeof(*point)); + } + } else { + mWatchpointListCopy(list, &debugger->watchpoints); + } } static void ARMDebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { @@ -505,12 +529,12 @@ static void ARMDebuggerFrameFormatRegisters(struct mStackFrame* frame, char* out ARMDebuggerFormatRegisters(frame->regs, out, length); } -static uint32_t ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform* d) { +static enum mStackTraceMode ARMDebuggerGetStackTraceMode(struct mDebuggerPlatform* d) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; return debugger->stackTraceMode; } -static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform* d, uint32_t mode) { +static void ARMDebuggerSetStackTraceMode(struct mDebuggerPlatform* d, enum mStackTraceMode mode) { struct ARMDebugger* debugger = (struct ARMDebugger*) d; struct mStackTrace* stack = &d->p->stackTrace; if (mode == STACK_TRACE_DISABLED && debugger->stackTraceMode != STACK_TRACE_DISABLED) { @@ -529,3 +553,27 @@ static bool ARMDebuggerUpdateStackTrace(struct mDebuggerPlatform* d) { return false; } } + +static void ARMDebuggerNextInstructionInfo(struct mDebuggerPlatform* d, struct mDebuggerInstructionInfo* info) { + struct ARMDebugger* debugger = (struct ARMDebugger*) d; + info->width = _ARMInstructionLength(debugger->cpu); + info->address = debugger->cpu->gprs[ARM_PC] - info->width; + info->segment = 0; + if (debugger->cpu->executionMode == MODE_ARM) { + info->flags[0] = mDebuggerAccessLogFlagsFillAccess32(0); + info->flags[1] = mDebuggerAccessLogFlagsFillAccess32(0); + info->flags[2] = mDebuggerAccessLogFlagsFillAccess32(0); + info->flags[3] = mDebuggerAccessLogFlagsFillAccess32(0); + info->flagsEx[0] = mDebuggerAccessLogFlagsExFillExecuteARM(0); + info->flagsEx[1] = mDebuggerAccessLogFlagsExFillExecuteARM(0); + info->flagsEx[2] = mDebuggerAccessLogFlagsExFillExecuteARM(0); + info->flagsEx[3] = mDebuggerAccessLogFlagsExFillExecuteARM(0); + } else { + info->flags[0] = mDebuggerAccessLogFlagsFillAccess16(0); + info->flags[1] = mDebuggerAccessLogFlagsFillAccess16(0); + info->flagsEx[0] = mDebuggerAccessLogFlagsExFillExecuteThumb(0); + info->flagsEx[1] = mDebuggerAccessLogFlagsExFillExecuteThumb(0); + } + + // TODO Access types +} diff --git a/src/arm/debugger/memory-debugger.c b/src/arm/debugger/memory-debugger.c index 85c9995ae..7dce87795 100644 --- a/src/arm/debugger/memory-debugger.c +++ b/src/arm/debugger/memory-debugger.c @@ -12,7 +12,7 @@ #include -static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width); +static void _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, enum mWatchpointType type, uint32_t newValue, int width); #define FIND_DEBUGGER(DEBUGGER, CPU) \ do { \ @@ -39,10 +39,7 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st static RETURN DebuggerShim_ ## NAME TYPES { \ struct ARMDebugger* debugger; \ FIND_DEBUGGER(debugger, cpu); \ - struct mDebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_READ, 0, WIDTH)) { \ - mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \ - } \ + _checkWatchpoints(debugger, address, WATCHPOINT_READ, 0, WIDTH); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ } @@ -50,10 +47,7 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st static RETURN DebuggerShim_ ## NAME TYPES { \ struct ARMDebugger* debugger; \ FIND_DEBUGGER(debugger, cpu); \ - struct mDebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_WRITE, value, WIDTH)) { \ - mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \ - } \ + _checkWatchpoints(debugger, address, WATCHPOINT_WRITE, value, WIDTH); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ } @@ -73,10 +67,7 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st } \ unsigned i; \ for (i = 0; i < popcount; ++i) { \ - struct mDebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, base + 4 * i, &info, ACCESS_TYPE, 0, 4)) { \ - mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \ - } \ + _checkWatchpoints(debugger, base + 4 * i, ACCESS_TYPE, 0, 4); \ } \ return debugger->originalMemory.NAME(cpu, address, mask, direction, cycleCounter); \ } @@ -91,7 +82,7 @@ CREATE_MULTIPLE_WATCHPOINT_SHIM(loadMultiple, WATCHPOINT_READ) CREATE_MULTIPLE_WATCHPOINT_SHIM(storeMultiple, WATCHPOINT_WRITE) CREATE_SHIM(setActiveRegion, void, (struct ARMCore* cpu, uint32_t address), address) -static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint32_t newValue, int width) { +static void _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, enum mWatchpointType type, uint32_t newValue, int width) { struct mWatchpoint* watchpoint; size_t i; uint32_t minAddress = address & ~(width - 1); @@ -124,16 +115,20 @@ static bool _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, st if ((watchpoint->type & WATCHPOINT_CHANGE) && newValue == oldValue) { continue; } - info->type.wp.oldValue = oldValue; - info->type.wp.newValue = newValue; - info->address = address; - info->type.wp.watchType = watchpoint->type; - info->type.wp.accessType = type; - info->pointId = watchpoint->id; - return true; + + struct mDebuggerEntryInfo info; + info.type.wp.oldValue = oldValue; + info.type.wp.newValue = newValue; + info.type.wp.watchType = watchpoint->type; + info.type.wp.accessType = type; + info.address = address; + info.segment = 0; + info.width = width; + info.pointId = watchpoint->id; + info.target = TableLookup(&debugger->d.p->pointOwner, watchpoint->id); + mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); } } - return false; } void ARMDebuggerInstallMemoryShim(struct ARMDebugger* debugger) { diff --git a/src/arm/decoder.c b/src/arm/decoder.c index 1c98c3002..01622cc9d 100644 --- a/src/arm/decoder.c +++ b/src/arm/decoder.c @@ -573,7 +573,7 @@ uint32_t ARMResolveMemoryAccess(struct ARMInstructionInfo* info, struct ARMRegis if (info->memory.format & ARM_MEMORY_IMMEDIATE_OFFSET) { offset = info->memory.offset.immediate; } else if (info->memory.format & ARM_MEMORY_REGISTER_OFFSET) { - offset = info->memory.offset.reg == ARM_PC ? pc : regs->gprs[info->memory.offset.reg]; + offset = info->memory.offset.reg == ARM_PC ? pc : (uint32_t) regs->gprs[info->memory.offset.reg]; } if (info->memory.format & ARM_MEMORY_SHIFTED_OFFSET) { uint8_t shiftSize = info->memory.offset.shifterImm; diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index b3bb3c9da..7f158dc6e 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -663,7 +663,9 @@ DEFINE_INSTRUCTION_ARM(MRC, ARM_STUB) // Begin miscellaneous definitions -DEFINE_INSTRUCTION_ARM(BKPT, cpu->irqh.bkpt32(cpu, ((opcode >> 4) & 0xFFF0) | (opcode & 0xF))); // Not strictly in ARMv4T, but here for convenience +DEFINE_INSTRUCTION_ARM(BKPT, + cpu->irqh.bkpt32(cpu, ((opcode >> 4) & 0xFFF0) | (opcode & 0xF)); + currentCycles = 0;); // Not strictly in ARMv4T, but here for convenience DEFINE_INSTRUCTION_ARM(ILL, ARM_ILL) // Illegal opcode DEFINE_INSTRUCTION_ARM(MSR, diff --git a/src/arm/isa-thumb.c b/src/arm/isa-thumb.c index 6e3c30e11..0bc8fcb12 100644 --- a/src/arm/isa-thumb.c +++ b/src/arm/isa-thumb.c @@ -381,7 +381,9 @@ DEFINE_LOAD_STORE_MULTIPLE_THUMB(PUSHR, cpu->gprs[ARM_SP] = address) DEFINE_INSTRUCTION_THUMB(ILL, ARM_ILL) -DEFINE_INSTRUCTION_THUMB(BKPT, cpu->irqh.bkpt16(cpu, opcode & 0xFF);) +DEFINE_INSTRUCTION_THUMB(BKPT, + cpu->irqh.bkpt16(cpu, opcode & 0xFF); + currentCycles = 0;) // Not strictly in ARMv4T, but here for convenience DEFINE_INSTRUCTION_THUMB(B, int16_t immediate = (opcode & 0x07FF) << 5; cpu->gprs[ARM_PC] += (((int32_t) immediate) >> 4); @@ -401,11 +403,7 @@ DEFINE_INSTRUCTION_THUMB(BL2, DEFINE_INSTRUCTION_THUMB(BX, int rm = (opcode >> 3) & 0xF; _ARMSetMode(cpu, cpu->gprs[rm] & 0x00000001); - int misalign = 0; - if (rm == ARM_PC) { - misalign = cpu->gprs[rm] & 0x00000002; - } - cpu->gprs[ARM_PC] = (cpu->gprs[rm] & 0xFFFFFFFE) - misalign; + cpu->gprs[ARM_PC] = cpu->gprs[rm] & 0xFFFFFFFE; if (cpu->executionMode == MODE_THUMB) { currentCycles += ThumbWritePC(cpu); } else { diff --git a/src/core/cache-set.c b/src/core/cache-set.c index a638c786e..04d42a233 100644 --- a/src/core/cache-set.c +++ b/src/core/cache-set.c @@ -34,12 +34,15 @@ void mCacheSetDeinit(struct mCacheSet* cache) { for (i = 0; i < mMapCacheSetSize(&cache->maps); ++i) { mMapCacheDeinit(mMapCacheSetGetPointer(&cache->maps, i)); } + mMapCacheSetDeinit(&cache->maps); for (i = 0; i < mBitmapCacheSetSize(&cache->bitmaps); ++i) { mBitmapCacheDeinit(mBitmapCacheSetGetPointer(&cache->bitmaps, i)); } + mBitmapCacheSetDeinit(&cache->bitmaps); for (i = 0; i < mTileCacheSetSize(&cache->tiles); ++i) { mTileCacheDeinit(mTileCacheSetGetPointer(&cache->tiles, i)); } + mTileCacheSetDeinit(&cache->tiles); } void mCacheSetAssignVRAM(struct mCacheSet* cache, void* vram) { diff --git a/src/core/cheats.c b/src/core/cheats.c index 688b32ebe..60f73abcc 100644 --- a/src/core/cheats.c +++ b/src/core/cheats.c @@ -489,8 +489,10 @@ bool mCheatParseEZFChtFile(struct mCheatDevice* device, struct VFile* vf) { return false; } char* name = gbkToUtf8(&cheat[1], end - cheat - 1); - strncpy(cheatName, name, sizeof(cheatName) - 1); - free(name); + if (name) { + strncpy(cheatName, name, sizeof(cheatName) - 1); + free(name); + } cheatNameLength = strlen(cheatName); continue; } @@ -501,7 +503,10 @@ bool mCheatParseEZFChtFile(struct mCheatDevice* device, struct VFile* vf) { } if (strncmp(cheat, "ON", eq - cheat) != 0) { char* subname = gbkToUtf8(cheat, eq - cheat); - snprintf(&cheatName[cheatNameLength], sizeof(cheatName) - cheatNameLength - 1, ": %s", subname); + if (subname) { + snprintf(&cheatName[cheatNameLength], sizeof(cheatName) - cheatNameLength - 1, ": %s", subname); + free(subname); + } } set = device->createSet(device, cheatName); set->enabled = false; diff --git a/src/core/config.c b/src/core/config.c index 6bfcb8e8b..4d4733cd9 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -79,7 +79,7 @@ static const char* _lookupValue(const struct mCoreConfig* config, const char* ke static bool _lookupCharValue(const struct mCoreConfig* config, const char* key, char** out) { const char* value = _lookupValue(config, key); - if (!value) { + if (!value || !value[0]) { return false; } if (*out) { @@ -169,14 +169,14 @@ void mCoreConfigDeinit(struct mCoreConfig* config) { #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 bool mCoreConfigLoad(struct mCoreConfig* config) { - char path[PATH_MAX]; + char path[PATH_MAX + 1]; mCoreConfigDirectory(path, PATH_MAX); strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path)); return mCoreConfigLoadPath(config, path); } bool mCoreConfigSave(const struct mCoreConfig* config) { - char path[PATH_MAX]; + char path[PATH_MAX + 1]; mCoreConfigDirectory(path, PATH_MAX); strncat(path, PATH_SEP "config.ini", PATH_MAX - strlen(path)); return mCoreConfigSavePath(config, path); @@ -198,38 +198,46 @@ bool mCoreConfigSaveVFile(const struct mCoreConfig* config, struct VFile* vf) { return ConfigurationWriteVFile(&config->configTable, vf); } -void mCoreConfigMakePortable(const struct mCoreConfig* config) { +void mCoreConfigMakePortable(const struct mCoreConfig* config, const char* path) { struct VFile* portable = NULL; + struct Configuration portableConfig; char out[PATH_MAX]; - mCoreConfigPortablePath(out, sizeof(out)); + mCoreConfigPortableIniPath(out, sizeof(out)); if (!out[0]) { // Cannot be made portable return; } - portable = VFileOpen(out, O_WRONLY | O_CREAT); + + ConfigurationInit(&portableConfig); + + portable = VFileOpen(out, O_RDONLY); if (portable) { + ConfigurationReadVFile(&portableConfig, portable); portable->close(portable); - mCoreConfigSave(config); } + + if (path && path[0]) { + ConfigurationSetValue(&portableConfig, "portable", "path", path); + } else { + ConfigurationClearValue(&portableConfig, "portable", "path"); + } + + portable = VFileOpen(out, O_WRONLY | O_CREAT | O_TRUNC); + if (portable) { + ConfigurationWriteVFile(&portableConfig, portable); + portable->close(portable); + } + + ConfigurationDeinit(&portableConfig); + mCoreConfigSave(config); } void mCoreConfigDirectory(char* out, size_t outLength) { - struct VFile* portable; char portableDir[PATH_MAX]; mCoreConfigPortablePath(portableDir, sizeof(portableDir)); if (portableDir[0]) { - portable = VFileOpen(portableDir, O_RDONLY); - if (portable) { - portable->close(portable); - if (outLength < PATH_MAX) { - char outTmp[PATH_MAX]; - separatePath(portableDir, outTmp, NULL, NULL); - strlcpy(out, outTmp, outLength); - } else { - separatePath(portableDir, out, NULL, NULL); - } - return; - } + strlcpy(out, portableDir, outLength); + return; } #ifdef _WIN32 WCHAR wpath[MAX_PATH]; @@ -276,11 +284,10 @@ void mCoreConfigDirectory(char* out, size_t outLength) { #endif } -void mCoreConfigPortablePath(char* out, size_t outLength) { +void mCoreConfigPortableIniPath(char* out, size_t outLength) { #ifdef _WIN32 wchar_t wpath[MAX_PATH]; - HMODULE hModule = GetModuleHandleW(NULL); - GetModuleFileNameW(hModule, wpath, MAX_PATH); + GetModuleFileNameW(NULL, wpath, MAX_PATH); PathRemoveFileSpecW(wpath); if (PATH_SEP[0] != '\\') { WCHAR* pathSep; @@ -291,6 +298,7 @@ void mCoreConfigPortablePath(char* out, size_t outLength) { WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, outLength, 0, 0); StringCchCatA(out, outLength, PATH_SEP "portable.ini"); #elif defined(PSP2) || defined(GEKKO) || defined(__SWITCH__) || defined(__3DS__) + UNUSED(outLength); out[0] = '\0'; #else getcwd(out, outLength); @@ -304,22 +312,48 @@ void mCoreConfigPortablePath(char* out, size_t outLength) { CFRelease(suburl); } #endif - strncat(out, PATH_SEP "portable.ini", outLength - strlen(out)); + strncat(out, PATH_SEP "portable.ini", outLength - strlen(out) - 1); #endif } -bool mCoreConfigIsPortable(void) { - struct VFile* portable; - char portableDir[PATH_MAX]; - mCoreConfigPortablePath(portableDir, sizeof(portableDir)); - if (portableDir[0]) { - portable = VFileOpen(portableDir, O_RDONLY); - if (portable) { - portable->close(portable); - return true; +void mCoreConfigPortablePath(char* out, size_t outLength) { + struct VFile* portableIni; + char portableIniPath[PATH_MAX]; + mCoreConfigPortableIniPath(portableIniPath, sizeof(portableIniPath)); + out[0] = '\0'; + if (portableIniPath[0]) { + portableIni = VFileOpen(portableIniPath, O_RDONLY); + if (portableIni) { + // Start with the path that the portable.ini file exists in. + char iniDir[PATH_MAX]; + separatePath(portableIniPath, iniDir, NULL, NULL); + strlcpy(out, iniDir, outLength); + + struct Configuration portableConfig; + ConfigurationInit(&portableConfig); + if (ConfigurationReadVFile(&portableConfig, portableIni)) { + const char* path = ConfigurationGetValue(&portableConfig, "portable", "path"); + if (path) { + if (path[0] == '/') { + // User specified an absolute path. + strlcpy(out, path, outLength); + } else { + // User specified a relative path, append to the portable.ini path. + snprintf(out, outLength, "%s" PATH_SEP "%s", iniDir, path); + } + } + } + ConfigurationDeinit(&portableConfig); + + portableIni->close(portableIni); } } - return false; +} + +bool mCoreConfigIsPortable(void) { + char portableDir[PATH_MAX]; + mCoreConfigPortablePath(portableDir, sizeof(portableDir)); + return portableDir[0]; } #endif @@ -407,6 +441,7 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) _lookupIntValue(config, "frameskip", &opts->frameskip); _lookupIntValue(config, "volume", &opts->volume); _lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity); + _lookupIntValue(config, "rewindBufferInterval", &opts->rewindBufferInterval); _lookupFloatValue(config, "fpsTarget", &opts->fpsTarget); unsigned audioBuffers; if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) { @@ -449,6 +484,7 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "frameskip", opts->frameskip); ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindEnable", opts->rewindEnable); ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity); + ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferInterval", opts->rewindBufferInterval); ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget); ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers); ConfigurationSetUIntValue(&config->defaultsTable, 0, "sampleRate", opts->sampleRate); diff --git a/src/core/core-serialize.c b/src/core/core-serialize.c index d4cc7abed..ee5e6389f 100644 --- a/src/core/core-serialize.c +++ b/src/core/core-serialize.c @@ -13,7 +13,7 @@ #include #ifdef USE_PNG -#include +#include #include #include #endif @@ -176,15 +176,15 @@ static bool _savePNGState(struct mCore* core, struct VFile* vf, struct mStateExt mappedMemoryFree(state, stateSize); unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); png_structp png = PNGWriteOpen(vf); - png_infop info = PNGWriteHeader(png, width, height); + png_infop info = PNGWriteHeader(png, width, height, mCOLOR_NATIVE); if (!png || !info) { PNGWriteClose(png, info); free(buffer); return false; } - PNGWritePixels(png, width, height, stride, pixels); + PNGWritePixels(png, width, height, stride, pixels, mCOLOR_NATIVE); PNGWriteCustomChunk(png, "gbAs", len, buffer); if (extdata) { uint32_t i; @@ -262,8 +262,18 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx PNGReadClose(png, info, end); return false; } - unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + + if (!PNGReadHeader(png, info)) { + PNGReadClose(png, info, end); + return false; + } + unsigned width = png_get_image_width(png, info); + unsigned height = png_get_image_height(png, info); + if (width > 0x4000 || height > 0x4000) { + // These images are ridiculously large...let's assume a DOS attempt and reject + PNGReadClose(png, info, end); + return false; + } uint32_t* pixels = malloc(width * height * 4); if (!pixels) { PNGReadClose(png, info, end); @@ -278,8 +288,8 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx .extdata = extdata }; + bool success = true; PNGInstallChunkHandler(png, &bundle, _loadPNGChunkHandler, "gbAs gbAx"); - bool success = PNGReadHeader(png, info); success = success && PNGReadPixels(png, info, pixels, width, height, width); success = success && PNGReadFooter(png, end); PNGReadClose(png, info, end); @@ -295,6 +305,12 @@ static void* _loadPNGState(struct mCore* core, struct VFile* vf, struct mStateEx .clean = free }; mStateExtdataPut(extdata, EXTDATA_SCREENSHOT, &item); + + uint16_t dims[2] = { width, height }; + item.size = sizeof(dims); + item.data = malloc(item.size); + memcpy(item.data, dims, item.size); + mStateExtdataPut(extdata, EXTDATA_SCREENSHOT_DIMENSIONS, &item); } else { free(pixels); } @@ -437,7 +453,7 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { UNUSED(flags); #endif vf->truncate(vf, stateSize); - struct GBASerializedState* state = vf->map(vf, stateSize, MAP_WRITE); + void* state = vf->map(vf, stateSize, MAP_WRITE); if (!state) { mStateExtdataDeinit(&extdata); if (cheatVf) { @@ -513,7 +529,7 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { mappedMemoryFree(state, core->stateSize(core)); unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); struct mStateExtdataItem item; if (flags & SAVESTATE_SCREENSHOT && mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item)) { diff --git a/src/core/core.c b/src/core/core.c index c4c3a3ce8..a7de23943 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -87,7 +87,7 @@ struct mCore* mCoreCreate(enum mPlatform platform) { } #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 -#include +#include #ifdef PSP2 #include @@ -127,6 +127,7 @@ struct mCore* mCoreFind(const char* path) { } bool mCoreLoadFile(struct mCore* core, const char* path) { + core->unloadROM(core); #ifdef FIXED_ROM_BUFFER return mCorePreloadFile(core, path); #else @@ -361,11 +362,11 @@ bool mCoreTakeScreenshotVF(struct mCore* core, struct VFile* vf) { size_t stride; const void* pixels = 0; unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); core->getPixels(core, &pixels, &stride); png_structp png = PNGWriteOpen(vf); - png_infop info = PNGWriteHeader(png, width, height); - bool success = PNGWritePixels(png, width, height, stride, pixels); + png_infop info = PNGWriteHeader(png, width, height, mCOLOR_NATIVE); + bool success = PNGWritePixels(png, width, height, stride, pixels, mCOLOR_NATIVE); PNGWriteClose(png, info); return success; #else diff --git a/src/core/directories.c b/src/core/directories.c index 63c66e564..c35773f1e 100644 --- a/src/core/directories.c +++ b/src/core/directories.c @@ -116,10 +116,15 @@ struct VFile* mDirectorySetOpenSuffix(struct mDirectorySet* dirs, struct VDir* d } void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptions* opts) { + char abspath[PATH_MAX + 1]; + char configDir[PATH_MAX + 1]; + mCoreConfigDirectory(configDir, sizeof(configDir)); + if (opts->savegamePath) { - struct VDir* dir = VDirOpen(opts->savegamePath); - if (!dir && VDirCreate(opts->savegamePath)) { - dir = VDirOpen(opts->savegamePath); + makeAbsolute(opts->savegamePath, configDir, abspath); + struct VDir* dir = VDirOpen(abspath); + if (!dir && VDirCreate(abspath)) { + dir = VDirOpen(abspath); } if (dir) { if (dirs->save && dirs->save != dirs->base) { @@ -130,9 +135,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio } if (opts->savestatePath) { - struct VDir* dir = VDirOpen(opts->savestatePath); - if (!dir && VDirCreate(opts->savestatePath)) { - dir = VDirOpen(opts->savestatePath); + makeAbsolute(opts->savestatePath, configDir, abspath); + struct VDir* dir = VDirOpen(abspath); + if (!dir && VDirCreate(abspath)) { + dir = VDirOpen(abspath); } if (dir) { if (dirs->state && dirs->state != dirs->base) { @@ -143,9 +149,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio } if (opts->screenshotPath) { - struct VDir* dir = VDirOpen(opts->screenshotPath); - if (!dir && VDirCreate(opts->screenshotPath)) { - dir = VDirOpen(opts->screenshotPath); + makeAbsolute(opts->screenshotPath, configDir, abspath); + struct VDir* dir = VDirOpen(abspath); + if (!dir && VDirCreate(abspath)) { + dir = VDirOpen(abspath); } if (dir) { if (dirs->screenshot && dirs->screenshot != dirs->base) { @@ -156,9 +163,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio } if (opts->patchPath) { - struct VDir* dir = VDirOpen(opts->patchPath); - if (!dir && VDirCreate(opts->patchPath)) { - dir = VDirOpen(opts->patchPath); + makeAbsolute(opts->patchPath, configDir, abspath); + struct VDir* dir = VDirOpen(abspath); + if (!dir && VDirCreate(abspath)) { + dir = VDirOpen(abspath); } if (dir) { if (dirs->patch && dirs->patch != dirs->base) { @@ -169,9 +177,10 @@ void mDirectorySetMapOptions(struct mDirectorySet* dirs, const struct mCoreOptio } if (opts->cheatsPath) { - struct VDir* dir = VDirOpen(opts->cheatsPath); - if (!dir && VDirCreate(opts->cheatsPath)) { - dir = VDirOpen(opts->cheatsPath); + makeAbsolute(opts->cheatsPath, configDir, abspath); + struct VDir* dir = VDirOpen(abspath); + if (!dir && VDirCreate(abspath)) { + dir = VDirOpen(abspath); } if (dir) { if (dirs->cheats && dirs->cheats != dirs->base) { diff --git a/src/core/flags.h.in b/src/core/flags.h.in index 71ea562ef..3bd142a44 100644 --- a/src/core/flags.h.in +++ b/src/core/flags.h.in @@ -79,6 +79,10 @@ #cmakedefine USE_GDB_STUB #endif +#ifndef USE_JSON_C +#cmakedefine USE_JSON_C +#endif + #ifndef USE_LIBAV #cmakedefine USE_LIBAV #endif @@ -95,6 +99,10 @@ #cmakedefine USE_LIBZIP #endif +#ifndef USE_LUA +#cmakedefine USE_LUA +#endif + #ifndef USE_LZMA #cmakedefine USE_LZMA #endif @@ -121,8 +129,44 @@ // HAVE flags +#ifndef HAVE_CRC32 +#cmakedefine HAVE_CRC32 +#endif + +#ifndef HAVE_LOCALTIME_R +#cmakedefine HAVE_LOCALTIME_R +#endif + #ifndef HAVE_POPCOUNT32 #cmakedefine HAVE_POPCOUNT32 #endif +#ifndef HAVE_PTHREAD_NP_H +#cmakedefine HAVE_PTHREAD_NP_H +#endif + +#ifndef HAVE_PTHREAD_SETNAME_NP +#cmakedefine HAVE_PTHREAD_SETNAME_NP +#endif + +#ifndef HAVE_STRDUP +#cmakedefine HAVE_STRDUP +#endif + +#ifndef HAVE_STRLCPY +#cmakedefine HAVE_STRLCPY +#endif + +#ifndef HAVE_STRDUP +#cmakedefine HAVE_STRDUP +#endif + +#ifndef HAVE_STRTOF_L +#cmakedefine HAVE_STRTOF_L +#endif + +#ifndef HAVE_XLOCALE +#cmakedefine HAVE_XLOCALE +#endif + #endif diff --git a/src/core/input.c b/src/core/input.c index 76296a373..1c06d48a9 100644 --- a/src/core/input.c +++ b/src/core/input.c @@ -9,8 +9,6 @@ #include #include -#include - #define SECTION_NAME_MAX 128 #define KEY_NAME_MAX 32 #define KEY_VALUE_MAX 16 @@ -38,6 +36,11 @@ struct mInputAxisEnumerate { void* user; }; +struct mInputHatEnumerate { + void (*handler)(int axis, const struct mInputHatBindings* bindings, void* user); + void* user; +}; + static void _makeSectionName(const char* platform, char* sectionName, size_t len, uint32_t type) { snprintf(sectionName, len, "%s.input.%c%c%c%c", platform, type >> 24, type >> 16, type >> 8, type); sectionName[len - 1] = '\0'; @@ -304,6 +307,12 @@ void _unbindAxis(uint32_t axis, void* dp, void* user) { } } +void _enumerateHat(uint32_t axis, void* dp, void* ep) { + struct mInputHatEnumerate* enumUser = ep; + const struct mInputHatBindings* description = dp; + enumUser->handler(axis, description, enumUser->user); +} + static bool _loadAll(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) { if (!ConfigurationHasSection(config, sectionName)) { return false; @@ -415,6 +424,16 @@ void mInputUnbindKey(struct mInputMap* map, uint32_t type, int input) { } } +void mInputUnbindAllKeys(struct mInputMap* map, uint32_t type) { + struct mInputMapImpl* impl = _lookupMap(map, type); + if (impl) { + size_t i; + for (i = 0; i < map->info->nKeys; ++i) { + impl->map[i] = -1; + } + } +} + int mInputQueryBinding(const struct mInputMap* map, uint32_t type, int input) { if (input < 0 || (size_t) input >= map->info->nKeys) { return -1; @@ -578,6 +597,18 @@ void mInputUnbindAllHats(struct mInputMap* map, uint32_t type) { } } +void mInputEnumerateHats(const struct mInputMap* map, uint32_t type, void (handler(int hat, const struct mInputHatBindings* bindings, void* user)), void* user) { + const struct mInputMapImpl* impl = _lookupMapConst(map, type); + if (!impl) { + return; + } + struct mInputHatEnumerate enumUser = { + handler, + user + }; + TableEnumerate(&impl->axes, _enumerateHat, &enumUser); +} + bool mInputMapLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config) { char sectionName[SECTION_NAME_MAX]; _makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type); diff --git a/src/core/log.c b/src/core/log.c index 2d90fe05e..b897fedb4 100644 --- a/src/core/log.c +++ b/src/core/log.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #define MAX_CATEGORY 64 @@ -14,11 +14,56 @@ static struct mLogger* _defaultLogger = NULL; -struct mLogger* mLogGetContext(void) { - struct mLogger* logger = NULL; #ifndef DISABLE_THREADING - logger = mCoreThreadLogger(); +static ThreadLocal _contextKey; + +#ifdef USE_PTHREADS +static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT; + +static void _createTLS(void) { + ThreadLocalInitKey(&_contextKey); +} +#elif _WIN32 +static INIT_ONCE _contextOnce = INIT_ONCE_STATIC_INIT; + +static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) { + UNUSED(once); + UNUSED(param); + UNUSED(context); + ThreadLocalInitKey(&_contextKey); + return TRUE; +} #endif + +static void _setupTLS(void) { +#ifdef USE_PTHREADS + pthread_once(&_contextOnce, _createTLS); +#elif _WIN32 + InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0); +#endif +} +#endif + +void mLogSetThreadLogger(struct mLogger* logger) { +#ifndef DISABLE_THREADING + _setupTLS(); + ThreadLocalSetKey(_contextKey, logger); +#else + UNUSED(logger); +#endif +} + +struct mLogger* mLogGetThreadLogger(void) { +#ifndef DISABLE_THREADING + _setupTLS(); + return ThreadLocalGetValue(_contextKey); +#else + return NULL; +#endif +} + +struct mLogger* mLogGetContext(void) { + struct mLogger* logger = mLogGetThreadLogger(); if (logger) { return logger; } @@ -50,7 +95,7 @@ const char* mLogCategoryName(int category) { } const char* mLogCategoryId(int category) { - if (category < MAX_CATEGORY) { + if (category >= 0 && category < MAX_CATEGORY) { return _categoryIds[category]; } return NULL; @@ -88,6 +133,7 @@ void mLogExplicit(struct mLogger* context, int category, enum mLogLevel level, c if (!context->filter || mLogFilterTest(context->filter, category, level)) { context->log(context, category, level, format, args); } + va_end(args); } void mLogFilterInit(struct mLogFilter* filter) { diff --git a/src/core/rewind.c b/src/core/rewind.c index 95f47ece4..21120ec21 100644 --- a/src/core/rewind.c +++ b/src/core/rewind.c @@ -30,6 +30,7 @@ void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries, context->previousState = VFileMemChunk(0, 0); context->currentState = VFileMemChunk(0, 0); context->size = 0; + context->rewindFrameCounter = 0; #ifndef DISABLE_THREADING context->onThread = onThread; context->ready = false; @@ -175,7 +176,7 @@ THREAD_ENTRY _rewindThread(void* context) { rewindContext->ready = false; } MutexUnlock(&rewindContext->mutex); - return 0; + THREAD_EXIT(0); } #endif diff --git a/src/core/scripting.c b/src/core/scripting.c index 05433b747..5b1f39a63 100644 --- a/src/core/scripting.c +++ b/src/core/scripting.c @@ -7,6 +7,10 @@ #include #include +#ifdef M_CORE_GBA +#include +#endif +#include #include #include #include @@ -155,10 +159,49 @@ struct mScriptMemoryDomain { struct mCoreMemoryBlock block; }; +#ifdef USE_DEBUGGERS +struct mScriptBreakpointName { + uint32_t address; + uint32_t maxAddress; + int16_t segment; + uint8_t type; + uint8_t subtype; +}; + +struct mScriptBreakpoint { + ssize_t id; + struct mScriptBreakpointName name; + struct Table callbacks; +}; + +struct mScriptCoreAdapter; +struct mScriptDebugger { + struct mDebuggerModule d; + struct mScriptCoreAdapter* p; + struct Table breakpoints; + struct Table cbidMap; + struct Table bpidMap; + int64_t nextBreakpoint; +}; +#endif + struct mScriptCoreAdapter { struct mCore* core; struct mScriptContext* context; struct mScriptValue memory; +#ifdef USE_DEBUGGERS + struct mScriptDebugger debugger; +#endif + struct mRumble rumble; + struct mRumble* oldRumble; + struct mRotationSource rotation; + struct mScriptValue* rotationCbTable; + struct mRotationSource* oldRotation; +#ifdef M_CORE_GBA + struct GBALuminanceSource luminance; + struct mScriptValue* luminanceCb; + struct GBALuminanceSource* oldLuminance; +#endif }; struct mScriptConsole { @@ -399,6 +442,7 @@ static int _mScriptCoreLoadStateFile(struct mCore* core, const char* path, int f vf->close(vf); return ok; } + static void _mScriptCoreTakeScreenshot(struct mCore* core, const char* filename) { if (filename) { struct VFile* vf = VFileOpen(filename, O_WRONLY | O_CREAT | O_TRUNC); @@ -412,6 +456,29 @@ static void _mScriptCoreTakeScreenshot(struct mCore* core, const char* filename) } } +static struct mScriptValue* _mScriptCoreTakeScreenshotToImage(struct mCore* core) { + size_t stride; + const void* pixels = 0; + unsigned width, height; + core->currentVideoSize(core, &width, &height); + core->getPixels(core, &pixels, &stride); + if (!pixels) { + return NULL; + } +#ifndef COLOR_16_BIT + struct mImage* image = mImageCreateFromConstBuffer(width, height, stride, mCOLOR_XBGR8, pixels); +#elif COLOR_5_6_5 + struct mImage* image = mImageCreateFromConstBuffer(width, height, stride, mCOLOR_RGB565, pixels); +#else + struct mImage* image = mImageCreateFromConstBuffer(width, height, stride, mCOLOR_BGR5, pixels); +#endif + + struct mScriptValue* result = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mImage)); + result->value.opaque = image; + result->flags = mSCRIPT_VALUE_FLAG_DEINIT; + return result; +} + // Loading functions mSCRIPT_DECLARE_STRUCT_METHOD(mCore, BOOL, loadFile, mCoreLoadFile, 1, CHARP, path); mSCRIPT_DECLARE_STRUCT_METHOD(mCore, BOOL, autoloadSave, mCoreAutoloadSave, 0); @@ -464,6 +531,7 @@ mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mCore, BOOL, loadStateFile, _mScript // Miscellaneous functions mSCRIPT_DECLARE_STRUCT_VOID_METHOD_WITH_DEFAULTS(mCore, screenshot, _mScriptCoreTakeScreenshot, 1, CHARP, filename); +mSCRIPT_DECLARE_STRUCT_METHOD(mCore, W(mImage), screenshotToImage, _mScriptCoreTakeScreenshotToImage, 0); mSCRIPT_DEFINE_STRUCT(mCore) mSCRIPT_DEFINE_CLASS_DOCSTRING( @@ -549,8 +617,10 @@ mSCRIPT_DEFINE_STRUCT(mCore) mSCRIPT_DEFINE_DOCSTRING("Load state from the given path. See C.SAVESTATE for possible values for `flags`") mSCRIPT_DEFINE_STRUCT_METHOD(mCore, loadStateFile) - mSCRIPT_DEFINE_DOCSTRING("Save a screenshot") + mSCRIPT_DEFINE_DOCSTRING("Save a screenshot to a file") mSCRIPT_DEFINE_STRUCT_METHOD(mCore, screenshot) + mSCRIPT_DEFINE_DOCSTRING("Get a screenshot in an struct::mImage") + mSCRIPT_DEFINE_STRUCT_METHOD(mCore, screenshotToImage) mSCRIPT_DEFINE_END; mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mCore, checksum) @@ -631,9 +701,239 @@ static void _rebuildMemoryMap(struct mScriptContext* context, struct mScriptCore } } +#ifdef USE_DEBUGGERS +static void _freeBreakpoint(void* bp) { + struct mScriptBreakpoint* point = bp; + HashTableDeinit(&point->callbacks); + free(bp); +} + +static struct mScriptBreakpoint* _ensureBreakpoint(struct mScriptDebugger* debugger, struct mBreakpoint* breakpoint) { + struct mDebuggerModule* module = &debugger->d; + struct mScriptBreakpointName name = { + .address = breakpoint->address, + .maxAddress = 0, + .segment = breakpoint->segment, + .type = 0, + .subtype = breakpoint->type + }; + struct mScriptBreakpoint* point = HashTableLookupBinary(&debugger->breakpoints, &name, sizeof(name)); + if (point) { + return point; + } + point = calloc(1, sizeof(*point)); + point->id = module->p->platform->setBreakpoint(module->p->platform, module, breakpoint); + point->name = name; + HashTableInit(&point->callbacks, 0, (void (*)(void*)) mScriptValueDeref); + HashTableInsertBinary(&debugger->bpidMap, &point->id, sizeof(point->id), point); + HashTableInsertBinary(&debugger->breakpoints, &name, sizeof(name), point); + return point; +} + +static struct mScriptBreakpoint* _ensureWatchpoint(struct mScriptDebugger* debugger, struct mWatchpoint* watchpoint) { + struct mDebuggerModule* module = &debugger->d; + struct mScriptBreakpointName name = { + .address = watchpoint->minAddress, + .maxAddress = watchpoint->maxAddress, + .segment = watchpoint->segment, + .type = 1, + .subtype = watchpoint->type + }; + struct mScriptBreakpoint* point = HashTableLookupBinary(&debugger->breakpoints, &name, sizeof(name)); + if (point) { + return point; + } + point = calloc(1, sizeof(*point)); + point->id = module->p->platform->setWatchpoint(module->p->platform, module, watchpoint); + point->name = name; + HashTableInit(&point->callbacks, 0, (void (*)(void*)) mScriptValueDeref); + HashTableInsertBinary(&debugger->bpidMap, &point->id, sizeof(point->id), point); + HashTableInsertBinary(&debugger->breakpoints, &name, sizeof(name), point); + return point; +} + +static int64_t _addCallbackToBreakpoint(struct mScriptDebugger* debugger, struct mScriptBreakpoint* point, struct mScriptValue* callback) { + int64_t cbid = debugger->nextBreakpoint; + ++debugger->nextBreakpoint; + HashTableInsertBinary(&debugger->cbidMap, &cbid, sizeof(cbid), point); + mScriptValueRef(callback); + HashTableInsertBinary(&point->callbacks, &cbid, sizeof(cbid), callback); + return cbid; +} + +static void _runCallbacks(struct mScriptDebugger* debugger, struct mScriptBreakpoint* point) { + struct TableIterator iter; + if (!HashTableIteratorStart(&point->callbacks, &iter)) { + return; + } + do { + struct mScriptValue* fn = HashTableIteratorGetValue(&point->callbacks, &iter); + struct mScriptFrame frame; + mScriptFrameInit(&frame); + mScriptContextInvoke(debugger->p->context, fn, &frame); + mScriptFrameDeinit(&frame); + } while (HashTableIteratorNext(&point->callbacks, &iter)); +} + +static void _scriptDebuggerInit(struct mDebuggerModule* debugger) { + struct mScriptDebugger* scriptDebugger = (struct mScriptDebugger*) debugger; + debugger->isPaused = false; + debugger->needsCallback = false; + + HashTableInit(&scriptDebugger->breakpoints, 0, _freeBreakpoint); + HashTableInit(&scriptDebugger->cbidMap, 0, NULL); + HashTableInit(&scriptDebugger->bpidMap, 0, NULL); +} + +static void _scriptDebuggerDeinit(struct mDebuggerModule* debugger) { + struct mScriptDebugger* scriptDebugger = (struct mScriptDebugger*) debugger; + HashTableDeinit(&scriptDebugger->cbidMap); + HashTableDeinit(&scriptDebugger->bpidMap); + HashTableDeinit(&scriptDebugger->breakpoints); +} + +static void _scriptDebuggerPaused(struct mDebuggerModule* debugger, int32_t timeoutMs) { + UNUSED(debugger); + UNUSED(timeoutMs); +} + +static void _scriptDebuggerUpdate(struct mDebuggerModule* debugger) { + UNUSED(debugger); +} + +static void _scriptDebuggerEntered(struct mDebuggerModule* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + struct mScriptDebugger* scriptDebugger = (struct mScriptDebugger*) debugger; + struct mScriptBreakpoint* point; + switch (reason) { + case DEBUGGER_ENTER_BREAKPOINT: + case DEBUGGER_ENTER_WATCHPOINT: + point = HashTableLookupBinary(&scriptDebugger->bpidMap, &info->pointId, sizeof(info->pointId)); + break; + default: + return; + } + _runCallbacks(scriptDebugger, point); + debugger->isPaused = false; +} + +static void _scriptDebuggerCustom(struct mDebuggerModule* debugger) { + UNUSED(debugger); +} + +static void _scriptDebuggerInterrupt(struct mDebuggerModule* debugger) { + UNUSED(debugger); +} + +static bool _setupDebugger(struct mScriptCoreAdapter* adapter) { + if (!adapter->core->debugger) { + return false; + } + + if (adapter->debugger.d.p) { + return true; + } + adapter->debugger.p = adapter; + adapter->debugger.d.type = DEBUGGER_CUSTOM; + adapter->debugger.d.init = _scriptDebuggerInit; + adapter->debugger.d.deinit = _scriptDebuggerDeinit; + adapter->debugger.d.paused = _scriptDebuggerPaused; + adapter->debugger.d.update = _scriptDebuggerUpdate; + adapter->debugger.d.entered = _scriptDebuggerEntered; + adapter->debugger.d.custom = _scriptDebuggerCustom; + adapter->debugger.d.interrupt = _scriptDebuggerInterrupt; + adapter->debugger.d.isPaused = false; + adapter->debugger.d.needsCallback = false; + adapter->debugger.nextBreakpoint = 1; + mDebuggerAttachModule(adapter->core->debugger, &adapter->debugger.d); + return true; +} + +static int64_t _mScriptCoreAdapterSetBreakpoint(struct mScriptCoreAdapter* adapter, struct mScriptValue* callback, uint32_t address, int32_t segment) { + if (!_setupDebugger(adapter)) { + return -1; + } + struct mBreakpoint breakpoint = { + .address = address, + .segment = segment, + .type = BREAKPOINT_HARDWARE + }; + + struct mDebuggerModule* module = &adapter->debugger.d; + if (!module->p->platform->setBreakpoint) { + return -1; + } + struct mScriptBreakpoint* point = _ensureBreakpoint(&adapter->debugger, &breakpoint); + return _addCallbackToBreakpoint(&adapter->debugger, point, callback); +} + +static int64_t _mScriptCoreAdapterSetWatchpoint(struct mScriptCoreAdapter* adapter, struct mScriptValue* callback, uint32_t address, int type, int32_t segment) { + if (!_setupDebugger(adapter)) { + return -1; + } + + struct mWatchpoint watchpoint = { + .minAddress = address, + .maxAddress = address + 1, + .segment = segment, + .type = type, + }; + struct mDebuggerModule* module = &adapter->debugger.d; + if (!module->p->platform->setWatchpoint) { + return -1; + } + struct mScriptBreakpoint* point = _ensureWatchpoint(&adapter->debugger, &watchpoint); + return _addCallbackToBreakpoint(&adapter->debugger, point, callback); +} + +static int64_t _mScriptCoreAdapterSetRangeWatchpoint(struct mScriptCoreAdapter* adapter, struct mScriptValue* callback, uint32_t minAddress, uint32_t maxAddress, int type, int32_t segment) { + if (!_setupDebugger(adapter)) { + return -1; + } + + struct mWatchpoint watchpoint = { + .minAddress = minAddress, + .maxAddress = maxAddress, + .segment = segment, + .type = type, + }; + struct mDebuggerModule* module = &adapter->debugger.d; + if (!module->p->platform->setWatchpoint) { + return -1; + } + struct mScriptBreakpoint* point = _ensureWatchpoint(&adapter->debugger, &watchpoint); + return _addCallbackToBreakpoint(&adapter->debugger, point, callback); +} + +static bool _mScriptCoreAdapterClearBreakpoint(struct mScriptCoreAdapter* adapter, int64_t cbid) { + if (!_setupDebugger(adapter)) { + return false; + } + struct mScriptBreakpoint* point = HashTableLookupBinary(&adapter->debugger.cbidMap, &cbid, sizeof(cbid)); + if (!point) { + return false; + } + HashTableRemoveBinary(&adapter->debugger.cbidMap, &cbid, sizeof(cbid)); + HashTableRemoveBinary(&point->callbacks, &cbid, sizeof(cbid)); + + if (!HashTableSize(&point->callbacks)) { + struct mDebuggerModule* module = &adapter->debugger.d; + module->p->platform->clearBreakpoint(module->p->platform, point->id); + + struct mScriptBreakpointName name = point->name; + HashTableRemoveBinary(&adapter->debugger.breakpoints, &name, sizeof(name)); + } + return true; +} +#endif + static void _mScriptCoreAdapterDeinit(struct mScriptCoreAdapter* adapter) { _clearMemoryMap(adapter->context, adapter, false); adapter->memory.type->free(&adapter->memory); +#ifdef USE_DEBUGGERS + if (adapter->core->debugger) { + mDebuggerDetachModule(adapter->core->debugger, &adapter->debugger.d); + } +#endif } static struct mScriptValue* _mScriptCoreAdapterGet(struct mScriptCoreAdapter* adapter, const char* name) { @@ -651,13 +951,64 @@ static struct mScriptValue* _mScriptCoreAdapterGet(struct mScriptCoreAdapter* ad static void _mScriptCoreAdapterReset(struct mScriptCoreAdapter* adapter) { adapter->core->reset(adapter->core); - mScriptContextTriggerCallback(adapter->context, "reset"); + mScriptContextTriggerCallback(adapter->context, "reset", NULL); +} + +static struct mScriptValue* _mScriptCoreAdapterSetRotationCbTable(struct mScriptCoreAdapter* adapter, struct mScriptValue* cbTable) { + if (cbTable) { + mScriptValueRef(cbTable); + } + struct mScriptValue* oldTable = adapter->rotationCbTable; + adapter->rotationCbTable = cbTable; + return oldTable; +} + +static void _mScriptCoreAdapterSetLuminanceCb(struct mScriptCoreAdapter* adapter, struct mScriptValue* callback) { + if (callback) { + if (callback->type->base != mSCRIPT_TYPE_FUNCTION) { + return; + } + mScriptValueRef(callback); + } + if (adapter->luminanceCb) { + mScriptValueDeref(adapter->luminanceCb); + } + adapter->luminanceCb = callback; } mSCRIPT_DECLARE_STRUCT(mScriptCoreAdapter); mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, W(mCore), _get, _mScriptCoreAdapterGet, 1, CHARP, name); mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, _deinit, _mScriptCoreAdapterDeinit, 0); mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, reset, _mScriptCoreAdapterReset, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, WTABLE, setRotationCallbacks, _mScriptCoreAdapterSetRotationCbTable, 1, WTABLE, cbTable); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCoreAdapter, setSolarSensorCallback, _mScriptCoreAdapterSetLuminanceCb, 1, WRAPPER, callback); +#ifdef USE_DEBUGGERS +mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptCoreAdapter, S64, setBreakpoint, _mScriptCoreAdapterSetBreakpoint, 3, WRAPPER, callback, U32, address, S32, segment); +mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptCoreAdapter, S64, setWatchpoint, _mScriptCoreAdapterSetWatchpoint, 4, WRAPPER, callback, U32, address, S32, type, S32, segment); +mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptCoreAdapter, S64, setRangeWatchpoint, _mScriptCoreAdapterSetRangeWatchpoint, 5, WRAPPER, callback, U32, minAddress, U32, maxAddress, S32, type, S32, segment); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCoreAdapter, BOOL, clearBreakpoint, _mScriptCoreAdapterClearBreakpoint, 1, S64, cbid); +#endif + +mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptCoreAdapter, setBreakpoint) + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_S32(-1) +mSCRIPT_DEFINE_DEFAULTS_END; + +mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptCoreAdapter, setWatchpoint) + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_S32(-1) +mSCRIPT_DEFINE_DEFAULTS_END; + +mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptCoreAdapter, setRangeWatchpoint) + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_S32(-1) +mSCRIPT_DEFINE_DEFAULTS_END; mSCRIPT_DEFINE_STRUCT(mScriptCoreAdapter) mSCRIPT_DEFINE_CLASS_DOCSTRING( @@ -672,10 +1023,157 @@ mSCRIPT_DEFINE_STRUCT(mScriptCoreAdapter) mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(mScriptCoreAdapter) mSCRIPT_DEFINE_DOCSTRING("Reset the emulation. As opposed to struct::mCore.reset, this version calls the **reset** callback") mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, reset) + mSCRIPT_DEFINE_DOCSTRING( + "Sets the table of functions to be called when the game requests rotation data, for either a gyroscope or accelerometer. " + "The following functions are supported, and if any isn't set then then default implementation for that function is called instead:\n\n" + "- `sample`: Update (\"sample\") the values returned by the other functions. The values returned shouldn't change until the next time this is called\n" + "- `readTiltX`: Return a value between -1.0 and +1.0 representing the X (left/right axis) direction of the linear acceleration vector, as for an accelerometer.\n" + "- `readTiltY`: Return a value between -1.0 and +1.0 representing the Y (up/down axis) direction of the linear acceleration vector, as for an accelerometer.\n" + "- `readGyroZ`: Return a value between -1.0 and +1.0 representing the roll (front/back axis) value of the rotational acceleration vector, as for an gyroscope.\n\n" + "Optionally, you can also set a value `context` on the table that will be passed to the callbacks. This table is copied by value, so changes made to the table " + "after being passed to this function will not be seen unless the function is called again. Therefore, the recommended usage of the `context` field is as an index " + "or key into a separate table. Use cases may vary. If this function is called more than once, the previous value of the table is returned." + ) + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setRotationCallbacks) + mSCRIPT_DEFINE_DOCSTRING( + "Set a callback that will be used to get the current value of the solar sensors between 0 (darkest) and 255 (brightest). " + "Note that the full range of values is not used by games, and the exact range depends on the calibration done by the game itself." + ) + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setSolarSensorCallback) +#ifdef USE_DEBUGGERS + mSCRIPT_DEFINE_DOCSTRING("Set a breakpoint at a given address") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setBreakpoint) + mSCRIPT_DEFINE_DOCSTRING("Clear a breakpoint or watchpoint for a given id returned by a previous call") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, clearBreakpoint) + mSCRIPT_DEFINE_DOCSTRING("Set a watchpoint at a given address of a given type") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setWatchpoint) + mSCRIPT_DEFINE_DOCSTRING( + "Set a watchpoint in a given range of a given type. Note that the range is exclusive on the end, " + "as though you've added the size, i.e. a 4-byte watch would specify the maximum as the minimum address + 4" + ) + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCoreAdapter, setRangeWatchpoint) +#endif mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(mScriptCoreAdapter, S(mCore), _core) mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(mScriptCoreAdapter, CS(mCore), _core) mSCRIPT_DEFINE_END; +static void _setRumble(struct mRumble* rumble, int enable) { + struct mScriptCoreAdapter* adapter = containerof(rumble, struct mScriptCoreAdapter, rumble); + + if (adapter->oldRumble) { + adapter->oldRumble->setRumble(adapter->oldRumble, enable); + } + + struct mScriptList args; + mScriptListInit(&args, 1); + *mScriptListAppend(&args) = mSCRIPT_MAKE_BOOL(!!enable); + mScriptContextTriggerCallback(adapter->context, "rumble", &args); + mScriptListDeinit(&args); +} + +static bool _callRotationCb(struct mScriptCoreAdapter* adapter, const char* cbName, struct mScriptValue* out) { + if (!adapter->rotationCbTable) { + return false; + } + struct mScriptValue* cb = mScriptTableLookup(adapter->rotationCbTable, &mSCRIPT_MAKE_CHARP(cbName)); + if (!cb || cb->type->base != mSCRIPT_TYPE_FUNCTION) { + return false; + } + struct mScriptFrame frame; + struct mScriptValue* context = mScriptTableLookup(adapter->rotationCbTable, &mSCRIPT_MAKE_CHARP("context")); + mScriptFrameInit(&frame); + if (context) { + mScriptValueWrap(context, mScriptListAppend(&frame.arguments)); + } + bool ok = mScriptContextInvoke(adapter->context, cb, &frame); + if (ok && out && mScriptListSize(&frame.returnValues) == 1) { + if (!mScriptCast(mSCRIPT_TYPE_MS_F32, mScriptListGetPointer(&frame.returnValues, 0), out)) { + ok = false; + } + } + mScriptFrameDeinit(&frame); + return ok; +} + +static void _rotationSample(struct mRotationSource* rotation) { + struct mScriptCoreAdapter* adapter = containerof(rotation, struct mScriptCoreAdapter, rotation); + + _callRotationCb(adapter, "sample", NULL); + + if (adapter->oldRotation && adapter->oldRotation->sample) { + adapter->oldRotation->sample(adapter->oldRotation); + } +} + +static int32_t _rotationReadTiltX(struct mRotationSource* rotation) { + struct mScriptCoreAdapter* adapter = containerof(rotation, struct mScriptCoreAdapter, rotation); + + struct mScriptValue out; + if (_callRotationCb(adapter, "readTiltX", &out)) { + return out.value.f32 * (double) INT32_MAX; + } + + if (adapter->oldRotation && adapter->oldRotation->readTiltX) { + return adapter->oldRotation->readTiltX(adapter->oldRotation); + } + return 0; +} + +static int32_t _rotationReadTiltY(struct mRotationSource* rotation) { + struct mScriptCoreAdapter* adapter = containerof(rotation, struct mScriptCoreAdapter, rotation); + + struct mScriptValue out; + if (_callRotationCb(adapter, "readTiltY", &out)) { + return out.value.f32 * (double) INT32_MAX; + } + + if (adapter->oldRotation && adapter->oldRotation->readTiltY) { + return adapter->oldRotation->readTiltY(adapter->oldRotation); + } + return 0; +} + +static int32_t _rotationReadGyroZ(struct mRotationSource* rotation) { + struct mScriptCoreAdapter* adapter = containerof(rotation, struct mScriptCoreAdapter, rotation); + + struct mScriptValue out; + if (_callRotationCb(adapter, "readGyroZ", &out)) { + return out.value.f32 * (double) INT32_MAX; + } + + if (adapter->oldRotation && adapter->oldRotation->readGyroZ) { + return adapter->oldRotation->readGyroZ(adapter->oldRotation); + } + return 0; +} + +#ifdef M_CORE_GBA +static uint8_t _readLuminance(struct GBALuminanceSource* luminance) { + struct mScriptCoreAdapter* adapter = containerof(luminance, struct mScriptCoreAdapter, luminance); + + if (adapter->luminanceCb) { + struct mScriptFrame frame; + mScriptFrameInit(&frame); + bool ok = mScriptContextInvoke(adapter->context, adapter->luminanceCb, &frame); + struct mScriptValue out = {0}; + if (ok && mScriptListSize(&frame.returnValues) == 1) { + if (!mScriptCast(mSCRIPT_TYPE_MS_U8, mScriptListGetPointer(&frame.returnValues, 0), &out)) { + ok = false; + } + } + mScriptFrameDeinit(&frame); + if (ok) { + return 0xFF - out.value.u32; + } + } + if (adapter->oldLuminance) { + adapter->oldLuminance->sample(adapter->oldLuminance); + return adapter->oldLuminance->readLuminance(adapter->oldLuminance); + } + return 0; +} +#endif + void mScriptContextAttachCore(struct mScriptContext* context, struct mCore* core) { struct mScriptValue* coreValue = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptCoreAdapter)); struct mScriptCoreAdapter* adapter = calloc(1, sizeof(*adapter)); @@ -687,6 +1185,25 @@ void mScriptContextAttachCore(struct mScriptContext* context, struct mCore* core adapter->memory.type = mSCRIPT_TYPE_MS_TABLE; adapter->memory.type->alloc(&adapter->memory); + adapter->rumble.setRumble = _setRumble; + adapter->rotation.sample = _rotationSample; + adapter->rotation.readTiltX = _rotationReadTiltX; + adapter->rotation.readTiltY = _rotationReadTiltY; + adapter->rotation.readGyroZ = _rotationReadGyroZ; + + adapter->oldRumble = core->getPeripheral(core, mPERIPH_RUMBLE); + adapter->oldRotation = core->getPeripheral(core, mPERIPH_ROTATION); + core->setPeripheral(core, mPERIPH_RUMBLE, &adapter->rumble); + core->setPeripheral(core, mPERIPH_ROTATION, &adapter->rotation); + +#ifdef M_CORE_GBA + adapter->luminance.readLuminance = _readLuminance; + if (core->platform(core) == mPLATFORM_GBA) { + adapter->oldLuminance = core->getPeripheral(core, mPERIPH_GBA_LUMINANCE); + core->setPeripheral(core, mPERIPH_GBA_LUMINANCE, &adapter->luminance); + } +#endif + _rebuildMemoryMap(context, adapter); coreValue->value.opaque = adapter; @@ -703,7 +1220,24 @@ void mScriptContextDetachCore(struct mScriptContext* context) { if (!value) { return; } - _clearMemoryMap(context, value->value.opaque, true); + + struct mScriptCoreAdapter* adapter = value->value.opaque; + _clearMemoryMap(context, adapter, true); + struct mCore* core = adapter->core; + core->setPeripheral(core, mPERIPH_RUMBLE, adapter->oldRumble); + core->setPeripheral(core, mPERIPH_ROTATION, adapter->oldRotation); + if (adapter->rotationCbTable) { + mScriptValueDeref(adapter->rotationCbTable); + } +#ifdef M_CORE_GBA + if (core->platform(core) == mPLATFORM_GBA) { + core->setPeripheral(core, mPERIPH_GBA_LUMINANCE, adapter->oldLuminance); + } + if (adapter->luminanceCb) { + mScriptValueDeref(adapter->luminanceCb); + } +#endif + mScriptContextRemoveGlobal(context, "emu"); } @@ -713,33 +1247,33 @@ static struct mScriptTextBuffer* _mScriptConsoleCreateBuffer(struct mScriptConso return buffer; } -static void mScriptConsoleLog(struct mScriptConsole* console, struct mScriptString* msg) { +static void mScriptConsoleLog(struct mScriptConsole* console, const char* msg) { if (console->logger) { - mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg->buffer); + mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg); } else { - mLog(_mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg->buffer); + mLog(_mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg); } } -static void mScriptConsoleWarn(struct mScriptConsole* console, struct mScriptString* msg) { +static void mScriptConsoleWarn(struct mScriptConsole* console, const char* msg) { if (console->logger) { - mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer); + mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg); } else { - mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer); + mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg); } } -static void mScriptConsoleError(struct mScriptConsole* console, struct mScriptString* msg) { +static void mScriptConsoleError(struct mScriptConsole* console, const char* msg) { if (console->logger) { - mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg->buffer); + mLogExplicit(console->logger, _mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg); } else { - mLog(_mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer); + mLog(_mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg); } } -mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, log, mScriptConsoleLog, 1, STR, msg); -mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, warn, mScriptConsoleWarn, 1, STR, msg); -mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, error, mScriptConsoleError, 1, STR, msg); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, log, mScriptConsoleLog, 1, CHARP, msg); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, warn, mScriptConsoleWarn, 1, CHARP, msg); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptConsole, error, mScriptConsoleError, 1, CHARP, msg); mSCRIPT_DECLARE_STRUCT_METHOD_WITH_DEFAULTS(mScriptConsole, S(mScriptTextBuffer), createBuffer, _mScriptConsoleCreateBuffer, 1, CHARP, name); mSCRIPT_DEFINE_STRUCT(mScriptConsole) @@ -761,14 +1295,16 @@ mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptConsole, createBuffer) mSCRIPT_DEFINE_DEFAULTS_END; static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) { - struct mScriptValue* value = mScriptContextEnsureGlobal(context, "console", mSCRIPT_TYPE_MS_S(mScriptConsole)); - struct mScriptConsole* console = value->value.opaque; - if (!console) { - console = calloc(1, sizeof(*console)); - value->value.opaque = console; - value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; - mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole"); + struct mScriptValue* value = mScriptContextGetGlobal(context, "console"); + if (value) { + return value->value.opaque; } + struct mScriptConsole* console = calloc(1, sizeof(*console)); + value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptConsole)); + value->value.opaque = console; + value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; + mScriptContextSetGlobal(context, "console", value); + mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole"); return console; } diff --git a/src/core/test/scripting.c b/src/core/test/scripting.c index 2e26b096f..c2593bf14 100644 --- a/src/core/test/scripting.c +++ b/src/core/test/scripting.c @@ -9,15 +9,14 @@ #include #include #include -#include -#include +#include #include "script/test.h" #ifdef M_CORE_GBA #include #define TEST_PLATFORM mPLATFORM_GBA -#define RAM_BASE BASE_WORKING_IRAM +#define RAM_BASE GBA_BASE_IWRAM #elif defined(M_CORE_GB) #include #define TEST_PLATFORM mPLATFORM_GB @@ -143,8 +142,8 @@ M_TEST_DEFINE(globals) { LOAD_PROGRAM("assert(emu)"); assert_true(lua->run(lua)); - TEARDOWN_CORE; mScriptContextDeinit(&context); + TEARDOWN_CORE; } M_TEST_DEFINE(infoFuncs) { @@ -161,8 +160,8 @@ M_TEST_DEFINE(infoFuncs) { TEST_VALUE(S32, "frequency", core->frequency(core)); TEST_VALUE(S32, "frameCycles", core->frameCycles(core)); - TEARDOWN_CORE; mScriptContextDeinit(&context); + TEARDOWN_CORE; } M_TEST_DEFINE(detach) { @@ -195,8 +194,8 @@ M_TEST_DEFINE(detach) { ); assert_false(lua->run(lua)); - TEARDOWN_CORE; mScriptContextDeinit(&context); + TEARDOWN_CORE; } M_TEST_DEFINE(runFrame) { @@ -215,8 +214,8 @@ M_TEST_DEFINE(runFrame) { TEST_VALUE(S32, "frame", i); } - TEARDOWN_CORE; mScriptContextDeinit(&context); + TEARDOWN_CORE; } M_TEST_DEFINE(memoryRead) { @@ -250,8 +249,8 @@ M_TEST_DEFINE(memoryRead) { TEST_VALUE(S32, "b16", 0x0807); TEST_VALUE(S32, "a32", 0x0C0B0A09); - TEARDOWN_CORE; mScriptContextDeinit(&context); + TEARDOWN_CORE; } M_TEST_DEFINE(memoryWrite) { @@ -278,8 +277,8 @@ M_TEST_DEFINE(memoryWrite) { assert_int_equal(core->busRead8(core, RAM_BASE + i), i + 1); } - TEARDOWN_CORE; mScriptContextDeinit(&context); + TEARDOWN_CORE; } M_TEST_DEFINE(logging) { @@ -310,6 +309,415 @@ M_TEST_DEFINE(logging) { mScriptContextDeinit(&context); } +M_TEST_DEFINE(screenshot) { + SETUP_LUA; + CREATE_CORE; + color_t* buffer = malloc(240 * 160 * sizeof(color_t)); + core->setVideoBuffer(core, buffer, 240); + core->reset(core); + core->runFrame(core); + + TEST_PROGRAM("im = emu:screenshotToImage()"); + TEST_PROGRAM("assert(im)"); + TEST_PROGRAM("assert(im.width >= 160)"); + TEST_PROGRAM("assert(im.height >= 144)"); + + free(buffer); + mScriptContextDeinit(&context); + TEARDOWN_CORE; +} + +#ifdef USE_DEBUGGERS +void _setupBp(struct mCore* core) { + switch (core->platform(core)) { +#ifdef M_CORE_GBA + case mPLATFORM_GBA: + core->busWrite32(core, 0x020000C0, 0xE0000000); // nop + core->busWrite32(core, 0x020000C4, 0xE0000000); // nop + core->busWrite32(core, 0x020000C8, 0xEAFFFFFD); // b 0x020000C4 + break; +#endif +#ifdef M_CORE_GB + case mPLATFORM_GB: + core->rawWrite8(core, 0x101, 0, 0xEE); // Jump to 0xF0 + core->rawWrite8(core, 0xF0, 0, 0x00); // nop + core->rawWrite8(core, 0xF1, 0, 0x18); // Loop forecer + core->rawWrite8(core, 0xF2, 0, 0xFD); // jr $-3 + break; +#endif + } +} + +#ifdef M_CORE_GBA +M_TEST_DEFINE(basicBreakpointGBA) { + SETUP_LUA; + struct mCore* core = mCoreCreate(mPLATFORM_GBA); + struct mDebugger debugger; + assert_non_null(core); + assert_true(core->init(core)); + mCoreInitConfig(core, NULL); + core->reset(core); + _setupBp(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt()\n" + " hit = hit + 1\n" + "end" + ); + TEST_PROGRAM("cbid = emu:setBreakpoint(bkpt, 0x020000C4)"); + TEST_PROGRAM("assert(cbid == 1)"); + + int i; + for (i = 0; i < 20; ++i) { + mDebuggerRun(&debugger); + } + + assert_int_equal(debugger.state, DEBUGGER_RUNNING); + TEST_PROGRAM("assert(hit >= 1)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} +#endif + +#ifdef M_CORE_GB +M_TEST_DEFINE(basicBreakpointGB) { + SETUP_LUA; + struct mCore* core = mCoreCreate(mPLATFORM_GB); + struct mDebugger debugger; + assert_non_null(core); + assert_true(core->init(core)); + mCoreInitConfig(core, NULL); + assert_true(core->loadROM(core, VFileFromConstMemory(_fakeGBROM, sizeof(_fakeGBROM)))); + core->reset(core); + _setupBp(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt()\n" + " hit = hit + 1\n" + "end" + ); + TEST_PROGRAM("cbid = emu:setBreakpoint(bkpt, 0xF0)"); + TEST_PROGRAM("assert(cbid == 1)"); + + int i; + for (i = 0; i < 20; ++i) { + mDebuggerRun(&debugger); + } + + assert_int_equal(debugger.state, DEBUGGER_RUNNING); + TEST_PROGRAM("assert(hit >= 1)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} +#endif + +M_TEST_DEFINE(multipleBreakpoint) { + SETUP_LUA; + struct mCore* core = mCoreCreate(TEST_PLATFORM); + struct mDebugger debugger; + assert_non_null(core); + assert_true(core->init(core)); + mCoreInitConfig(core, NULL); + core->reset(core); + _setupBp(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt1()\n" + " hit = hit + 1\n" + "end\n" + "function bkpt2()\n" + " hit = hit + 100\n" + "end" + ); +#ifdef M_CORE_GBA + TEST_PROGRAM("cbid1 = emu:setBreakpoint(bkpt1, 0x020000C4)"); + TEST_PROGRAM("cbid2 = emu:setBreakpoint(bkpt2, 0x020000C8)"); +#else + TEST_PROGRAM("cbid1 = emu:setBreakpoint(bkpt1, 0xF0)"); + TEST_PROGRAM("cbid2 = emu:setBreakpoint(bkpt2, 0xF1)"); +#endif + TEST_PROGRAM("assert(cbid1 == 1)"); + TEST_PROGRAM("assert(cbid2 == 2)"); + + int i; + for (i = 0; i < 20; ++i) { + mDebuggerRun(&debugger); + } + + assert_int_equal(debugger.state, DEBUGGER_RUNNING); + TEST_PROGRAM("assert(hit >= 101)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} + +M_TEST_DEFINE(basicWatchpoint) { + SETUP_LUA; + mScriptContextAttachStdlib(&context); + CREATE_CORE; + struct mDebugger debugger; + core->reset(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt()\n" + " hit = hit + 1\n" + "end" + ); + struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE); + lua->setGlobal(lua, "base", &base); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.READ))"); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base + 1, C.WATCHPOINT_TYPE.WRITE))"); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base + 2, C.WATCHPOINT_TYPE.RW))"); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base + 3, C.WATCHPOINT_TYPE.WRITE_CHANGE))"); + TEST_PROGRAM("assert(hit == 0)"); + + uint8_t value; + + // Read + TEST_PROGRAM("hit = 0"); + value = core->rawRead8(core, RAM_BASE, -1); + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE); + TEST_PROGRAM("assert(hit == 1)"); + core->busWrite8(core, RAM_BASE, value); + TEST_PROGRAM("assert(hit == 1)"); + core->busWrite8(core, RAM_BASE, ~value); + TEST_PROGRAM("assert(hit == 1)"); + + // Write + TEST_PROGRAM("hit = 0"); + value = core->rawRead8(core, RAM_BASE + 1, -1); + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE + 1); + TEST_PROGRAM("assert(hit == 0)"); + core->busWrite8(core, RAM_BASE + 1, value); + TEST_PROGRAM("assert(hit == 1)"); + core->busWrite8(core, RAM_BASE + 1, ~value); + TEST_PROGRAM("assert(hit == 2)"); + + // RW + TEST_PROGRAM("hit = 0"); + value = core->rawRead8(core, RAM_BASE + 2, -1); + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE + 2); + TEST_PROGRAM("assert(hit == 1)"); + core->busWrite8(core, RAM_BASE + 2, value); + TEST_PROGRAM("assert(hit == 2)"); + core->busWrite8(core, RAM_BASE + 2, ~value); + TEST_PROGRAM("assert(hit == 3)"); + + // Change + TEST_PROGRAM("hit = 0"); + value = core->rawRead8(core, RAM_BASE + 3, -1); + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE + 3); + TEST_PROGRAM("assert(hit == 0)"); + core->busWrite8(core, RAM_BASE + 3, value); + TEST_PROGRAM("assert(hit == 0)"); + core->busWrite8(core, RAM_BASE + 3, ~value); + TEST_PROGRAM("assert(hit == 1)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} + +M_TEST_DEFINE(removeBreakpoint) { + SETUP_LUA; + mScriptContextAttachStdlib(&context); + CREATE_CORE; + struct mDebugger debugger; + core->reset(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt()\n" + " hit = hit + 1\n" + "end" + ); + struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE); + lua->setGlobal(lua, "base", &base); + TEST_PROGRAM("cbid = emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.READ)"); + + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE); + TEST_PROGRAM("assert(hit == 1)"); + core->busRead8(core, RAM_BASE); + TEST_PROGRAM("assert(hit == 2)"); + TEST_PROGRAM("assert(emu:clearBreakpoint(cbid))"); + core->busRead8(core, RAM_BASE); + TEST_PROGRAM("assert(hit == 2)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} + + +M_TEST_DEFINE(overlappingBreakpoint) { + SETUP_LUA; + struct mCore* core = mCoreCreate(TEST_PLATFORM); + struct mDebugger debugger; + assert_non_null(core); + assert_true(core->init(core)); + mCoreInitConfig(core, NULL); + core->reset(core); + _setupBp(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt1()\n" + " hit = hit + 1\n" + "end\n" + "function bkpt2()\n" + " hit = hit + 100\n" + "end" + ); +#ifdef M_CORE_GBA + TEST_PROGRAM("cbid1 = emu:setBreakpoint(bkpt1, 0x020000C4)"); + TEST_PROGRAM("cbid2 = emu:setBreakpoint(bkpt2, 0x020000C4)"); +#else + TEST_PROGRAM("cbid1 = emu:setBreakpoint(bkpt1, 0xF0)"); + TEST_PROGRAM("cbid2 = emu:setBreakpoint(bkpt2, 0xF0)"); +#endif + TEST_PROGRAM("assert(cbid1 == 1)"); + TEST_PROGRAM("assert(cbid2 == 2)"); + + int i; + for (i = 0; i < 20; ++i) { + mDebuggerRun(&debugger); + } + + assert_int_equal(debugger.state, DEBUGGER_RUNNING); + TEST_PROGRAM("assert(hit >= 101)"); + TEST_PROGRAM("oldHit = hit"); + + TEST_PROGRAM("assert(emu:clearBreakpoint(cbid2))"); + + for (i = 0; i < 10; ++i) { + mDebuggerRun(&debugger); + } + TEST_PROGRAM("assert(hit - oldHit > 0)"); + TEST_PROGRAM("assert(hit - oldHit < 100)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} + +M_TEST_DEFINE(overlappingWatchpoint) { + SETUP_LUA; + mScriptContextAttachStdlib(&context); + CREATE_CORE; + struct mDebugger debugger; + core->reset(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt()\n" + " hit = hit + 1\n" + "end" + ); + struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE); + lua->setGlobal(lua, "base", &base); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.READ))"); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.WRITE))"); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.RW))"); + TEST_PROGRAM("assert(0 < emu:setWatchpoint(bkpt, base, C.WATCHPOINT_TYPE.WRITE_CHANGE))"); + TEST_PROGRAM("assert(hit == 0)"); + + uint8_t value; + + // Read + TEST_PROGRAM("hit = 0"); + value = core->rawRead8(core, RAM_BASE, -1); + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE); + TEST_PROGRAM("assert(hit == 2)"); // Read, RW + core->busWrite8(core, RAM_BASE, value); + TEST_PROGRAM("assert(hit == 4)"); // Write, RW + core->busWrite8(core, RAM_BASE, ~value); + TEST_PROGRAM("assert(hit == 7)"); // Write, RW, change + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} + +M_TEST_DEFINE(rangeWatchpoint) { + SETUP_LUA; + mScriptContextAttachStdlib(&context); + CREATE_CORE; + struct mDebugger debugger; + core->reset(core); + mScriptContextAttachCore(&context, core); + + mDebuggerInit(&debugger); + mDebuggerAttach(&debugger, core); + + TEST_PROGRAM( + "hit = 0\n" + "function bkpt()\n" + " hit = hit + 1\n" + "end" + ); + struct mScriptValue base = mSCRIPT_MAKE_S32(RAM_BASE); + lua->setGlobal(lua, "base", &base); + TEST_PROGRAM("assert(0 < emu:setRangeWatchpoint(bkpt, base, base + 2, C.WATCHPOINT_TYPE.READ))"); + TEST_PROGRAM("assert(0 < emu:setRangeWatchpoint(bkpt, base + 1, base + 3, C.WATCHPOINT_TYPE.READ))"); + + // Read + TEST_PROGRAM("assert(hit == 0)"); + core->busRead8(core, RAM_BASE); + TEST_PROGRAM("assert(hit == 1)"); + core->busRead8(core, RAM_BASE + 1); + TEST_PROGRAM("assert(hit == 3)"); + core->busRead8(core, RAM_BASE + 2); + TEST_PROGRAM("assert(hit == 4)"); + + mScriptContextDeinit(&context); + TEARDOWN_CORE; + mDebuggerDeinit(&debugger); +} +#endif + M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore, cmocka_unit_test(globals), cmocka_unit_test(infoFuncs), @@ -318,4 +726,19 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore, cmocka_unit_test(memoryRead), cmocka_unit_test(memoryWrite), cmocka_unit_test(logging), + cmocka_unit_test(screenshot), +#ifdef USE_DEBUGGERS +#ifdef M_CORE_GBA + cmocka_unit_test(basicBreakpointGBA), +#endif +#ifdef M_CORE_GB + cmocka_unit_test(basicBreakpointGB), +#endif + cmocka_unit_test(multipleBreakpoint), + cmocka_unit_test(basicWatchpoint), + cmocka_unit_test(removeBreakpoint), + cmocka_unit_test(overlappingBreakpoint), + cmocka_unit_test(overlappingWatchpoint), + cmocka_unit_test(rangeWatchpoint), +#endif ) diff --git a/src/core/thread.c b/src/core/thread.c index 7101b5a54..903d4b844 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -58,8 +58,19 @@ static void _waitOnInterrupt(struct mCoreThreadInternal* threadContext) { } static void _pokeRequest(struct mCoreThreadInternal* threadContext) { - if (threadContext->state == mTHREAD_RUNNING || threadContext->state == mTHREAD_PAUSED) { + switch (threadContext->state) { + case mTHREAD_RUNNING: + case mTHREAD_PAUSED: + case mTHREAD_CRASHED: threadContext->state = mTHREAD_REQUEST; + break; + case mTHREAD_INITIALIZED: + case mTHREAD_REQUEST: + case mTHREAD_INTERRUPTED: + case mTHREAD_INTERRUPTING: + case mTHREAD_EXITING: + case mTHREAD_SHUTDOWN: + break; } } @@ -98,10 +109,7 @@ static void _wait(struct mCoreThreadInternal* threadContext) { #ifdef USE_DEBUGGERS if (threadContext->core && threadContext->core->debugger) { - struct mDebugger* debugger = threadContext->core->debugger; - if (debugger->interrupt) { - debugger->interrupt(debugger); - } + mDebuggerInterrupt(threadContext->core->debugger); } #endif @@ -146,7 +154,11 @@ void _frameStarted(void* context) { } if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) { if (!thread->impl->rewinding || !mCoreRewindRestore(&thread->impl->rewind, thread->core)) { - mCoreRewindAppend(&thread->impl->rewind, thread->core); + if (thread->impl->rewind.rewindFrameCounter == 0) { + mCoreRewindAppend(&thread->impl->rewind, thread->core); + thread->impl->rewind.rewindFrameCounter = thread->core->opts.rewindBufferInterval; + } + thread->impl->rewind.rewindFrameCounter--; } } } @@ -194,7 +206,7 @@ void _script_ ## NAME(void* context) { \ if (!threadContext->scriptContext) { \ return; \ } \ - mScriptContextTriggerCallback(threadContext->scriptContext, #NAME); \ + mScriptContextTriggerCallback(threadContext->scriptContext, #NAME, NULL); \ } ADD_CALLBACK(frame) @@ -234,6 +246,8 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { ThreadLocalSetKey(_contextKey, threadContext); ThreadSetName("CPU Thread"); + mLogSetThreadLogger(&threadContext->logger.d); + #if !defined(_WIN32) && defined(USE_PTHREADS) sigset_t signals; sigemptyset(&signals); @@ -283,7 +297,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { } } if (scriptContext) { - mScriptContextTriggerCallback(scriptContext, "start"); + mScriptContextTriggerCallback(scriptContext, "start", NULL); } #endif @@ -304,7 +318,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { } } if (scriptContext) { - mScriptContextTriggerCallback(scriptContext, "reset"); + mScriptContextTriggerCallback(scriptContext, "reset", NULL); } #endif @@ -337,8 +351,8 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { while (impl->state >= mTHREAD_MIN_WAITING && impl->state <= mTHREAD_MAX_WAITING) { #ifdef USE_DEBUGGERS - if (debugger && debugger->update && debugger->state != DEBUGGER_SHUTDOWN) { - debugger->update(debugger); + if (debugger && debugger->state != DEBUGGER_SHUTDOWN) { + mDebuggerUpdate(debugger); ConditionWaitTimed(&impl->stateCond, &impl->stateMutex, 10); } else #endif @@ -404,7 +418,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { } #ifdef ENABLE_SCRIPTING if (scriptContext) { - mScriptContextTriggerCallback(scriptContext, "reset"); + mScriptContextTriggerCallback(scriptContext, "reset", NULL); } #endif } @@ -428,7 +442,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { } #ifdef ENABLE_SCRIPTING if (scriptContext) { - mScriptContextTriggerCallback(scriptContext, "shutdown"); + mScriptContextTriggerCallback(scriptContext, "shutdown", NULL); mScriptContextDetachCore(scriptContext); } #endif @@ -750,12 +764,3 @@ struct mCoreThread* mCoreThreadGet(void) { return NULL; } #endif - -struct mLogger* mCoreThreadLogger(void) { - struct mCoreThread* thread = mCoreThreadGet(); - if (thread) { - return &thread->logger.d; - } - return NULL; -} - diff --git a/src/debugger/CMakeLists.txt b/src/debugger/CMakeLists.txt index dde31390f..ce2ade635 100644 --- a/src/debugger/CMakeLists.txt +++ b/src/debugger/CMakeLists.txt @@ -1,5 +1,6 @@ include(ExportDirectory) set(SOURCE_FILES + access-logger.c cli-debugger.c debugger.c parser.c @@ -10,6 +11,14 @@ if(ENABLE_SCRIPTING) list(APPEND SOURCE_FILES cli-debugger-scripting.c) endif() +if(USE_EDITLINE) + list(APPEND SOURCE_FILES cli-el-backend.c) +endif() + +if(USE_GDB_STUB) + list(APPEND SOURCE_FILES gdb-stub.c) +endif() + set(TEST_FILES test/lexer.c test/parser.c) diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c new file mode 100644 index 000000000..41c780c4e --- /dev/null +++ b/src/debugger/access-logger.c @@ -0,0 +1,520 @@ +/* Copyright (c) 2013-2023 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 + +#include +#include + +#define DEFAULT_MAX_REGIONS 20 + +const char mAL_MAGIC[] = "mAL\1"; + +DEFINE_VECTOR(mDebuggerAccessLogRegionList, struct mDebuggerAccessLogRegion); + +DECL_BITFIELD(mDebuggerAccessLogHeaderFlags, uint64_t); + +struct mDebuggerAccessLogRegionInfo { + uint32_t start; + uint32_t end; + uint32_t size; + uint32_t segmentStart; + uint64_t fileOffset; + uint64_t fileOffsetEx; + mDebuggerAccessLogRegionFlags flags; + uint64_t reserved; +}; +static_assert(sizeof(struct mDebuggerAccessLogRegionInfo) == 0x30, "mDebuggerAccessLogRegionInfo struct sized wrong"); + +struct mDebuggerAccessLogHeader { + char magic[4]; + uint32_t version; + mDebuggerAccessLogHeaderFlags flags; + uint8_t nRegions; + uint8_t regionCapacity; + uint16_t padding; + uint32_t platform; + uint8_t reserved[0x28]; +}; +static_assert(sizeof(struct mDebuggerAccessLogHeader) == 0x40, "mDebuggerAccessLogHeader struct sized wrong"); + +struct mDebuggerAccessLog { + struct mDebuggerAccessLogHeader header; + struct mDebuggerAccessLogRegionInfo regionInfo[]; +}; + +static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + struct mDebuggerAccessLogger* logger = (struct mDebuggerAccessLogger*) debugger; + logger->d.isPaused = false; + + switch (reason) { + case DEBUGGER_ENTER_MANUAL: + case DEBUGGER_ENTER_ATTACHED: + return; + case DEBUGGER_ENTER_BREAKPOINT: + case DEBUGGER_ENTER_STACK: + mLOG(DEBUGGER, WARN, "Hit unexpected access logger entry type %i", reason); + return; + case DEBUGGER_ENTER_WATCHPOINT: + case DEBUGGER_ENTER_ILLEGAL_OP: + break; + } + + size_t i; + for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (info->address < region->start || info->address >= region->end) { + continue; + } + size_t offset = info->address - region->start; + if (info->segment > 0) { + uint32_t segmentSize = region->end - region->segmentStart; + offset %= segmentSize; + offset += segmentSize * info->segment; + } + + if (offset >= region->size) { + continue; + } + + offset &= -info->width; + + int j; + switch (reason) { + case DEBUGGER_ENTER_WATCHPOINT: + for (j = 0; j < info->width; ++j) { + if (info->type.wp.accessType & WATCHPOINT_WRITE) { + region->block[offset + j] = mDebuggerAccessLogFlagsFillWrite(region->block[offset + j]); + } + if (info->type.wp.accessType & WATCHPOINT_READ) { + region->block[offset + j] = mDebuggerAccessLogFlagsFillRead(region->block[offset + j]); + } + } + switch (info->width) { + case 1: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); + break; + case 2: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); + region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); + break; + case 4: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); + region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); + region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); + region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); + break; + case 8: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); + region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 1]); + region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 2]); + region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 3]); + region->block[offset + 4] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 4]); + region->block[offset + 5] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); + region->block[offset + 6] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); + region->block[offset + 7] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); + break; + } + break; + case DEBUGGER_ENTER_ILLEGAL_OP: + region->block[offset] = mDebuggerAccessLogFlagsFillExecute(region->block[offset]); + if (region->blockEx) { + uint16_t ex; + LOAD_16LE(ex, 0, ®ion->blockEx[offset]); + ex = mDebuggerAccessLogFlagsExFillErrorIllegalOpcode(ex); + STORE_16LE(ex, 0, ®ion->blockEx[offset]); + } + break; + default: + break; + } + } +} + +static void _mDebuggerAccessLoggerCallback(struct mDebuggerModule* debugger) { + struct mDebuggerAccessLogger* logger = (struct mDebuggerAccessLogger*) debugger; + + struct mDebuggerInstructionInfo info; + logger->d.p->platform->nextInstructionInfo(logger->d.p->platform, &info); + + size_t i; + for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (info.address < region->start || info.address >= region->end) { + continue; + } + size_t offset = info.address - region->start; + if (info.segment > 0) { + uint32_t segmentSize = region->end - region->segmentStart; + offset %= segmentSize; + offset += segmentSize * info.segment; + } + + if (offset >= region->size) { + continue; + } + + size_t j; + for (j = 0; j < info.width; ++j) { + uint16_t ex = 0; + region->block[offset + j] = mDebuggerAccessLogFlagsFillExecute(region->block[offset + j]); + region->block[offset + j] |= info.flags[j]; + + if (region->blockEx) { + LOAD_16LE(ex, 0, ®ion->blockEx[offset + j]); + ex |= info.flagsEx[j]; + STORE_16LE(ex, 0, ®ion->blockEx[offset + j]); + } + } + } +} + +void mDebuggerAccessLoggerInit(struct mDebuggerAccessLogger* logger) { + memset(logger, 0, sizeof(*logger)); + mDebuggerAccessLogRegionListInit(&logger->regions, 1); + + logger->d.type = DEBUGGER_ACCESS_LOGGER; + logger->d.entered = _mDebuggerAccessLoggerEntered; + logger->d.custom = _mDebuggerAccessLoggerCallback; +} + +void mDebuggerAccessLoggerDeinit(struct mDebuggerAccessLogger* logger) { + mDebuggerAccessLoggerClose(logger); + mDebuggerAccessLogRegionListDeinit(&logger->regions); +} + +static bool _mapRegion(struct mDebuggerAccessLogger* logger, struct mDebuggerAccessLogRegion* region, const struct mDebuggerAccessLogRegionInfo* info) { + uint64_t offset; + mDebuggerAccessLogRegionFlags flags; + + LOAD_64LE(offset, 0, &info->fileOffset); + LOAD_64LE(flags, 0, &info->flags); + +#if __SIZEOF_SIZE_T__ <= 4 + if (offset >= 0x100000000ULL) { + return false; + } +#endif + if (offset < sizeof(struct mDebuggerAccessLogHeader)) { + return false; + } + ssize_t fileEnd = logger->backing->size(logger->backing); + if (fileEnd < 0) { + return false; + } + if ((size_t) fileEnd <= offset) { + return false; + } + if ((size_t) fileEnd < offset + region->size * sizeof(mDebuggerAccessLogFlags)) { + return false; + } + region->block = (mDebuggerAccessLogFlags*) ((uintptr_t) logger->mapped + offset); + + if (mDebuggerAccessLogRegionFlagsIsHasExBlock(flags)) { + LOAD_64LE(offset, 0, &info->fileOffsetEx); +#if __SIZEOF_SIZE_T__ <= 4 + if (offset >= 0x100000000ULL) { + return false; + } +#endif + if (offset) { + if (offset < sizeof(struct mDebuggerAccessLogHeader)) { + return false; + } + if ((size_t) fileEnd <= offset) { + return false; + } + if ((size_t) fileEnd < offset + region->size * sizeof(mDebuggerAccessLogFlagsEx)) { + return false; + } + region->blockEx = (mDebuggerAccessLogFlagsEx*) ((uintptr_t) logger->mapped + offset); + } + } + return true; +} + +static bool _setupRegion(struct mDebuggerAccessLogger* logger, struct mDebuggerAccessLogRegion* region, const struct mDebuggerAccessLogRegionInfo* info) { + if (!_mapRegion(logger, region, info)) { + return false; + } + + struct mWatchpoint wp = { + .segment = -1, + .minAddress = region->start, + .maxAddress = region->end, + .type = WATCHPOINT_RW, + }; + logger->d.p->platform->setWatchpoint(logger->d.p->platform, &logger->d, &wp); + mDebuggerModuleSetNeedsCallback(&logger->d); + return true; +} + +static bool _remapAll(struct mDebuggerAccessLogger* logger) { + size_t i; + for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (!_mapRegion(logger, region, &logger->mapped->regionInfo[i])) { + return false; + } + } + return true; +} + +static bool mDebuggerAccessLoggerLoad(struct mDebuggerAccessLogger* logger) { + if (memcmp(logger->mapped->header.magic, mAL_MAGIC, sizeof(logger->mapped->header.magic)) != 0) { + return false; + } + uint32_t version; + LOAD_32LE(version, 0, &logger->mapped->header.version); + if (version != 1) { + return false; + } + + enum mPlatform platform; + LOAD_32LE(platform, 0, &logger->mapped->header.platform); + if (platform != logger->d.p->core->platform(logger->d.p->core)) { + return false; + } + + mDebuggerAccessLogRegionListClear(&logger->regions); + mDebuggerAccessLogRegionListResize(&logger->regions, logger->mapped->header.nRegions); + + size_t i; + for (i = 0; i < logger->mapped->header.nRegions; ++i) { + struct mDebuggerAccessLogRegionInfo* info = &logger->mapped->regionInfo[i]; + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + memset(region, 0, sizeof(*region)); + LOAD_32LE(region->start, 0, &info->start); + LOAD_32LE(region->end, 0, &info->end); + LOAD_32LE(region->size, 0, &info->size); + LOAD_32LE(region->segmentStart, 0, &info->segmentStart); + if (!_setupRegion(logger, region, info)) { + mDebuggerAccessLogRegionListClear(&logger->regions); + return false; + } + } + return true; +} + +bool mDebuggerAccessLoggerOpen(struct mDebuggerAccessLogger* logger, struct VFile* vf, int mode) { + if (logger->backing && !mDebuggerAccessLoggerClose(logger)) { + return false; + } + + ssize_t size = vf->size(vf); + if (size < 0) { + return false; + } + if ((size_t) size < sizeof(struct mDebuggerAccessLogHeader)) { + if (!(mode & O_CREAT)) { + return false; + } + vf->truncate(vf, sizeof(struct mDebuggerAccessLogHeader) + DEFAULT_MAX_REGIONS * sizeof(struct mDebuggerAccessLogRegionInfo)); + size = sizeof(struct mDebuggerAccessLogHeader); + } + + logger->mapped = vf->map(vf, size, MAP_WRITE); + if (!logger->mapped) { + return false; + } + logger->backing = vf; + bool loaded = false; + if (!(mode & O_TRUNC)) { + loaded = mDebuggerAccessLoggerLoad(logger); + } + if ((mode & O_CREAT) && ((mode & O_TRUNC) || !loaded)) { + memset(logger->mapped, 0, sizeof(*logger->mapped)); + memcpy(logger->mapped->header.magic, mAL_MAGIC, sizeof(logger->mapped->header.magic)); + STORE_32LE(1, 0, &logger->mapped->header.version); + STORE_32LE(DEFAULT_MAX_REGIONS, 0, &logger->mapped->header.regionCapacity); + vf->sync(vf, NULL, 0); + loaded = true; + } + return loaded; +} + +static int _mDebuggerAccessLoggerWatchMemoryBlock(struct mDebuggerAccessLogger* logger, const struct mCoreMemoryBlock* block, mDebuggerAccessLogRegionFlags flags) { + if (mDebuggerAccessLogRegionListSize(&logger->regions) >= logger->mapped->header.regionCapacity) { + return -1; + } + + if (!(block->flags & mCORE_MEMORY_MAPPED)) { + return -1; + } + + ssize_t fileEnd = logger->backing->size(logger->backing); + if (fileEnd < 0) { + return -1; + } + + size_t i; + for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (region->start != block->start) { + continue; + } + if (region->end != block->end) { + continue; + } + if (region->size != block->size) { + continue; + } + if (!region->blockEx && mDebuggerAccessLogRegionFlagsIsHasExBlock(flags)) { + size_t size = block->size * sizeof(mDebuggerAccessLogFlagsEx); + + logger->backing->unmap(logger->backing, logger->mapped, fileEnd); + logger->backing->truncate(logger->backing, fileEnd + size); + logger->mapped = logger->backing->map(logger->backing, fileEnd + size, MAP_WRITE); + + struct mDebuggerAccessLogRegionInfo* info = &logger->mapped->regionInfo[i]; + mDebuggerAccessLogRegionFlags oldFlags; + LOAD_64LE(oldFlags, 0, &info->flags); + oldFlags = mDebuggerAccessLogRegionFlagsFillHasExBlock(oldFlags); + + STORE_64LE(fileEnd, 0, &info->fileOffsetEx); + STORE_64LE(oldFlags, 0, &info->flags); + + logger->backing->sync(logger->backing, logger->mapped, sizeof(struct mDebuggerAccessLogHeader) + logger->mapped->header.regionCapacity * sizeof(struct mDebuggerAccessLogRegionInfo)); + + _remapAll(logger); + } + return i; + } + +#if __SIZEOF_SIZE_T__ <= 4 + if (block->size >= 0x80000000) { + return -1; + } +#endif + size_t size = block->size * sizeof(mDebuggerAccessLogFlags); + if (mDebuggerAccessLogRegionFlagsIsHasExBlock(flags)) { + size += block->size * sizeof(mDebuggerAccessLogFlagsEx); + } + logger->backing->unmap(logger->backing, logger->mapped, fileEnd); + logger->backing->truncate(logger->backing, fileEnd + size); + logger->mapped = logger->backing->map(logger->backing, fileEnd + size, MAP_WRITE); + + _remapAll(logger); + + int id = mDebuggerAccessLogRegionListSize(&logger->regions); + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListAppend(&logger->regions); + memset(region, 0, sizeof(*region)); + region->start = block->start; + region->end = block->end; + region->size = block->size; + region->segmentStart = block->segmentStart; + region->block = (mDebuggerAccessLogFlags*) ((uintptr_t) logger->backing + fileEnd); + + struct mDebuggerAccessLogRegionInfo* info = &logger->mapped->regionInfo[id]; + STORE_32LE(region->start, 0, &info->start); + STORE_32LE(region->end, 0, &info->end); + STORE_32LE(region->segmentStart, 0, &info->segmentStart); + STORE_64LE(fileEnd, 0, &info->fileOffset); + if (mDebuggerAccessLogRegionFlagsIsHasExBlock(flags)) { + STORE_64LE(fileEnd + block->size * sizeof(mDebuggerAccessLogFlags), 0, &info->fileOffsetEx); + } else { + STORE_64LE(0, 0, &info->fileOffsetEx); + } + STORE_64LE(flags, 0, &info->flags); + STORE_64LE(0, 0, &info->reserved); + STORE_32LE(region->size, 0, &info->size); + + logger->mapped->header.nRegions = id + 1; + + logger->backing->sync(logger->backing, logger->mapped, sizeof(struct mDebuggerAccessLogHeader) + logger->mapped->header.regionCapacity * sizeof(struct mDebuggerAccessLogRegionInfo)); + if (!_setupRegion(logger, region, info)) { + return -1; + } + return id; +} + +bool mDebuggerAccessLoggerClose(struct mDebuggerAccessLogger* logger) { + if (!logger->backing) { + return true; + } + mDebuggerAccessLogRegionListClear(&logger->regions); + logger->backing->unmap(logger->backing, logger->mapped, logger->backing->size(logger->backing)); + logger->mapped = NULL; + logger->backing->close(logger->backing); + logger->backing = NULL; + return true; +} + +int mDebuggerAccessLoggerWatchMemoryBlockId(struct mDebuggerAccessLogger* logger, size_t id, mDebuggerAccessLogRegionFlags flags) { + struct mCore* core = logger->d.p->core; + const struct mCoreMemoryBlock* blocks; + size_t nBlocks = core->listMemoryBlocks(core, &blocks); + + size_t i; + for (i = 0; i < nBlocks; ++i) { + if (blocks[i].id == id) { + return _mDebuggerAccessLoggerWatchMemoryBlock(logger, &blocks[i], flags); + } + } + return -1; +} + +int mDebuggerAccessLoggerWatchMemoryBlockName(struct mDebuggerAccessLogger* logger, const char* internalName, mDebuggerAccessLogRegionFlags flags) { + struct mCore* core = logger->d.p->core; + const struct mCoreMemoryBlock* blocks; + size_t nBlocks = core->listMemoryBlocks(core, &blocks); + + size_t i; + for (i = 0; i < nBlocks; ++i) { + if (strcmp(blocks[i].internalName, internalName) == 0) { + return _mDebuggerAccessLoggerWatchMemoryBlock(logger, &blocks[i], flags); + } + } + return -1; +} + +bool mDebuggerAccessLoggerCreateShadowFile(struct mDebuggerAccessLogger* logger, int regionId, struct VFile* vf, uint8_t fill) { + if (regionId < 0) { + return false; + } + if ((unsigned) regionId >= mDebuggerAccessLogRegionListSize(&logger->regions)) { + return false; + } + + if (vf->seek(vf, 0, SEEK_SET) < 0) { + return false; + } + struct mCore* core = logger->d.p->core; + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, regionId); + vf->truncate(vf, region->size); + + uint8_t buffer[0x800]; + int segment = 0; + uint32_t segmentAddress = region->start; + uint32_t segmentEnd = region->end; + + uint64_t i; + for (i = 0; i < region->size; ++i) { + if (segmentAddress == region->segmentStart && segmentAddress != region->start) { + ++segment; + } + if (segmentAddress == segmentEnd) { + segmentAddress = region->segmentStart; + ++segment; + } + if (region->block[i]) { + buffer[i & 0x7FF] = core->rawRead8(core, segmentAddress, segment); + } else { + buffer[i & 0x7FF] = fill; + } + if (i && (i & 0x7FF) == 0x7FF) { + if (vf->write(vf, buffer, 0x800) < 0) { + return false; + } + } + ++segmentAddress; + } + if (i & 0x7FF) { + if (vf->write(vf, buffer, i & 0x7FF) < 0) { + return false; + } + } + return true; +} diff --git a/src/debugger/cli-debugger.c b/src/debugger/cli-debugger.c index 12cd7af18..9c9696f9f 100644 --- a/src/debugger/cli-debugger.c +++ b/src/debugger/cli-debugger.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef USE_ELF #include #endif @@ -191,7 +192,7 @@ static void _breakInto(struct CLIDebugger* debugger, struct CLIDebugVector* dv) #endif static bool CLIDebuggerCheckTraceMode(struct CLIDebugger* debugger, bool requireEnabled) { - struct mDebuggerPlatform* platform = debugger->d.platform; + struct mDebuggerPlatform* platform = debugger->d.p->platform; if (!platform->getStackTraceMode) { debugger->backend->printf(debugger->backend, "Stack tracing is not supported by this platform.\n"); return false; @@ -204,13 +205,14 @@ static bool CLIDebuggerCheckTraceMode(struct CLIDebugger* debugger, bool require static void _continue(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - debugger->d.state = debugger->traceRemaining != 0 ? DEBUGGER_CALLBACK : DEBUGGER_RUNNING; + debugger->d.needsCallback = debugger->traceRemaining != 0; + debugger->d.isPaused = false; } static void _next(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - struct mDebuggerPlatform* platform = debugger->d.platform; - debugger->d.core->step(debugger->d.core); + struct mDebuggerPlatform* platform = debugger->d.p->platform; + debugger->d.p->core->step(debugger->d.p->core); if (platform->getStackTraceMode && platform->getStackTraceMode(platform) != STACK_TRACE_DISABLED) { platform->updateStackTrace(platform); } @@ -221,7 +223,7 @@ static void _disassemble(struct CLIDebugger* debugger, struct CLIDebugVector* dv debugger->system->disassemble(debugger->system, dv); } -static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector* dv, int32_t* intValue, int* segmentValue) { +static bool _parseExpression(struct mDebuggerModule* debugger, struct CLIDebugVector* dv, int32_t* intValue, int* segmentValue) { size_t args = 0; struct CLIDebugVector* accum; for (accum = dv; accum; accum = accum->next) { @@ -240,7 +242,7 @@ static bool _parseExpression(struct mDebugger* debugger, struct CLIDebugVector* if (!tree) { return false; } - if (!mDebuggerEvaluateParseTree(debugger, tree, intValue, segmentValue)) { + if (!mDebuggerEvaluateParseTree(debugger->p, tree, intValue, segmentValue)) { parseFree(tree); return false; } @@ -366,7 +368,7 @@ static void _printHelp(struct CLIDebugger* debugger, struct CLIDebugVector* dv) static void _quit(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - debugger->d.state = DEBUGGER_SHUTDOWN; + mDebuggerShutdown(debugger->d.p); } static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { @@ -377,17 +379,17 @@ static void _readByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { uint32_t address = dv->intValue; uint8_t value; if (dv->segmentValue >= 0) { - value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue); + value = debugger->d.p->core->rawRead8(debugger->d.p->core, address, dv->segmentValue); } else { - value = debugger->d.core->busRead8(debugger->d.core, address); + value = debugger->d.p->core->busRead8(debugger->d.p->core, address); } debugger->backend->printf(debugger->backend, " 0x%02X\n", value); } static void _reset(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - mStackTraceClear(&debugger->d.stackTrace); - debugger->d.core->reset(debugger->d.core); + mStackTraceClear(&debugger->d.p->stackTrace); + debugger->d.p->core->reset(debugger->d.p->core); _printStatus(debugger, 0); } @@ -399,9 +401,9 @@ static void _readHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d uint32_t address = dv->intValue; uint16_t value; if (dv->segmentValue >= 0) { - value = debugger->d.core->rawRead16(debugger->d.core, address & -1, dv->segmentValue); + value = debugger->d.p->core->rawRead16(debugger->d.p->core, address & -1, dv->segmentValue); } else { - value = debugger->d.core->busRead16(debugger->d.core, address & ~1); + value = debugger->d.p->core->busRead16(debugger->d.p->core, address & ~1); } debugger->backend->printf(debugger->backend, " 0x%04X\n", value); } @@ -414,9 +416,9 @@ static void _readWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { uint32_t address = dv->intValue; uint32_t value; if (dv->segmentValue >= 0) { - value = debugger->d.core->rawRead32(debugger->d.core, address & -3, dv->segmentValue); + value = debugger->d.p->core->rawRead32(debugger->d.p->core, address & -3, dv->segmentValue); } else { - value = debugger->d.core->busRead32(debugger->d.core, address & ~3); + value = debugger->d.p->core->busRead32(debugger->d.p->core, address & ~3); } debugger->backend->printf(debugger->backend, " 0x%08X\n", value); } @@ -437,9 +439,9 @@ static void _writeByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) return; } if (dv->segmentValue >= 0) { - debugger->d.core->rawWrite8(debugger->d.core, address, value, dv->segmentValue); + debugger->d.p->core->rawWrite8(debugger->d.p->core, address, dv->segmentValue, value); } else { - debugger->d.core->busWrite8(debugger->d.core, address, value); + debugger->d.p->core->busWrite8(debugger->d.p->core, address, value); } } @@ -459,9 +461,9 @@ static void _writeHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* return; } if (dv->segmentValue >= 0) { - debugger->d.core->rawWrite16(debugger->d.core, address, value, dv->segmentValue); + debugger->d.p->core->rawWrite16(debugger->d.p->core, address, dv->segmentValue, value); } else { - debugger->d.core->busWrite16(debugger->d.core, address, value); + debugger->d.p->core->busWrite16(debugger->d.p->core, address, value); } } @@ -474,7 +476,7 @@ static void _writeRegister(struct CLIDebugger* debugger, struct CLIDebugVector* debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); return; } - if (!debugger->d.core->writeRegister(debugger->d.core, dv->charValue, &dv->next->intValue)) { + if (!debugger->d.p->core->writeRegister(debugger->d.p->core, dv->charValue, &dv->next->intValue)) { debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); } } @@ -491,9 +493,9 @@ static void _writeWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) uint32_t address = dv->intValue; uint32_t value = dv->next->intValue; if (dv->segmentValue >= 0) { - debugger->d.core->rawWrite32(debugger->d.core, address, value, dv->segmentValue); + debugger->d.p->core->rawWrite32(debugger->d.p->core, address, dv->segmentValue, value); } else { - debugger->d.core->busWrite32(debugger->d.core, address, value); + debugger->d.p->core->busWrite32(debugger->d.p->core, address, value); } } @@ -516,9 +518,9 @@ static void _dumpByte(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { for (; line > 0; --line, ++address, --words) { uint32_t value; if (dv->segmentValue >= 0) { - value = debugger->d.core->rawRead8(debugger->d.core, address, dv->segmentValue); + value = debugger->d.p->core->rawRead8(debugger->d.p->core, address, dv->segmentValue); } else { - value = debugger->d.core->busRead8(debugger->d.core, address); + value = debugger->d.p->core->busRead8(debugger->d.p->core, address); } debugger->backend->printf(debugger->backend, " %02X", value); } @@ -545,9 +547,9 @@ static void _dumpHalfword(struct CLIDebugger* debugger, struct CLIDebugVector* d for (; line > 0; --line, address += 2, --words) { uint32_t value; if (dv->segmentValue >= 0) { - value = debugger->d.core->rawRead16(debugger->d.core, address, dv->segmentValue); + value = debugger->d.p->core->rawRead16(debugger->d.p->core, address, dv->segmentValue); } else { - value = debugger->d.core->busRead16(debugger->d.core, address); + value = debugger->d.p->core->busRead16(debugger->d.p->core, address); } debugger->backend->printf(debugger->backend, " %04X", value); } @@ -574,9 +576,9 @@ static void _dumpWord(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { for (; line > 0; --line, address += 4, --words) { uint32_t value; if (dv->segmentValue >= 0) { - value = debugger->d.core->rawRead32(debugger->d.core, address, dv->segmentValue); + value = debugger->d.p->core->rawRead32(debugger->d.p->core, address, dv->segmentValue); } else { - value = debugger->d.core->busRead32(debugger->d.core, address); + value = debugger->d.p->core->busRead32(debugger->d.p->core, address); } debugger->backend->printf(debugger->backend, " %08X", value); } @@ -590,8 +592,8 @@ static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { debugger->backend->printf(debugger->backend, "Needs a filename\n"); return; } - if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) { - mScriptBridgeRun(debugger->d.bridge); + if (debugger->d.p->bridge && mScriptBridgeLoadScript(debugger->d.p->bridge, dv->charValue)) { + mScriptBridgeRun(debugger->d.p->bridge); } else { debugger->backend->printf(debugger->backend, "Failed to load script\n"); } @@ -647,7 +649,7 @@ static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* return; } } - ssize_t id = debugger->d.platform->setBreakpoint(debugger->d.platform, &breakpoint); + ssize_t id = debugger->d.p->platform->setBreakpoint(debugger->d.p->platform, &debugger->d, &breakpoint); if (id > 0) { debugger->backend->printf(debugger->backend, INFO_BREAKPOINT_ADDED, id); } @@ -658,7 +660,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); return; } - if (!debugger->d.platform->setWatchpoint) { + if (!debugger->d.p->platform->setWatchpoint) { debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n"); return; } @@ -677,7 +679,7 @@ static void _setWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVector* return; } } - ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint); + ssize_t id = debugger->d.p->platform->setWatchpoint(debugger->d.p->platform, &debugger->d, &watchpoint); if (id > 0) { debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id); } @@ -692,7 +694,7 @@ static void _setRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); return; } - if (!debugger->d.platform->setWatchpoint) { + if (!debugger->d.p->platform->setWatchpoint) { debugger->backend->printf(debugger->backend, "Watchpoints are not supported by this platform.\n"); return; } @@ -719,7 +721,7 @@ static void _setRangeWatchpoint(struct CLIDebugger* debugger, struct CLIDebugVec return; } } - ssize_t id = debugger->d.platform->setWatchpoint(debugger->d.platform, &watchpoint); + ssize_t id = debugger->d.p->platform->setWatchpoint(debugger->d.p->platform, &debugger->d, &watchpoint); if (id > 0) { debugger->backend->printf(debugger->backend, INFO_WATCHPOINT_ADDED, id); } @@ -763,14 +765,14 @@ static void _clearBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector return; } uint64_t id = dv->intValue; - debugger->d.platform->clearBreakpoint(debugger->d.platform, id); + debugger->d.p->platform->clearBreakpoint(debugger->d.p->platform, id); } static void _listBreakpoints(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); struct mBreakpointList breakpoints; mBreakpointListInit(&breakpoints, 0); - debugger->d.platform->listBreakpoints(debugger->d.platform, &breakpoints); + debugger->d.p->platform->listBreakpoints(debugger->d.p->platform, &debugger->d, &breakpoints); size_t i; for (i = 0; i < mBreakpointListSize(&breakpoints); ++i) { struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&breakpoints, i); @@ -787,7 +789,7 @@ static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector UNUSED(dv); struct mWatchpointList watchpoints; mWatchpointListInit(&watchpoints, 0); - debugger->d.platform->listWatchpoints(debugger->d.platform, &watchpoints); + debugger->d.p->platform->listWatchpoints(debugger->d.p->platform, &debugger->d, &watchpoints); size_t i; for (i = 0; i < mWatchpointListSize(&watchpoints); ++i) { struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, i); @@ -809,16 +811,21 @@ static void _listWatchpoints(struct CLIDebugger* debugger, struct CLIDebugVector } static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - if (!dv || dv->type != CLIDV_INT_TYPE) { + if (!dv) { debugger->backend->printf(debugger->backend, "%s\n", ERROR_MISSING_ARGS); return; } + if (dv->type != CLIDV_INT_TYPE || dv->intValue < 0) { + debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); + return; + } debugger->traceRemaining = dv->intValue; if (debugger->traceVf) { debugger->traceVf->close(debugger->traceVf); debugger->traceVf = NULL; } + debugger->d.needsCallback = debugger->traceRemaining != 0; if (debugger->traceRemaining == 0) { return; } @@ -826,7 +833,8 @@ static void _trace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { debugger->traceVf = VFileOpen(dv->next->charValue, O_CREAT | O_WRONLY | O_APPEND); } if (_doTrace(debugger)) { - debugger->d.state = DEBUGGER_CALLBACK; + debugger->d.isPaused = false; + mDebuggerUpdatePaused(debugger->d.p); } else { debugger->system->printStatus(debugger->system); } @@ -836,7 +844,7 @@ static bool _doTrace(struct CLIDebugger* debugger) { char trace[1024]; trace[sizeof(trace) - 1] = '\0'; size_t traceSize = sizeof(trace) - 2; - debugger->d.platform->trace(debugger->d.platform, trace, &traceSize); + debugger->d.p->platform->trace(debugger->d.p->platform, trace, &traceSize); if (traceSize + 2 <= sizeof(trace)) { trace[traceSize] = '\n'; trace[traceSize + 1] = '\0'; @@ -854,6 +862,7 @@ static bool _doTrace(struct CLIDebugger* debugger) { debugger->traceVf->close(debugger->traceVf); debugger->traceVf = NULL; } + debugger->d.needsCallback = false; return false; } return true; @@ -866,7 +875,7 @@ static void _printStatus(struct CLIDebugger* debugger, struct CLIDebugVector* dv static void _events(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - struct mTiming* timing = debugger->d.core->timing; + struct mTiming* timing = debugger->d.p->core->timing; struct mTimingEvent* next = timing->root; for (; next; next = next->next) { debugger->backend->printf(debugger->backend, "%s in %i cycles\n", next->name, mTimingUntil(timing, next)); @@ -891,7 +900,7 @@ struct CLIDebugVector* CLIDVParse(struct CLIDebugger* debugger, const char* stri if (!parseLexedExpression(tree, &lv)) { dvTemp.type = CLIDV_ERROR_TYPE; } else { - if (!mDebuggerEvaluateParseTree(&debugger->d, tree, &dvTemp.intValue, &dvTemp.segmentValue)) { + if (!mDebuggerEvaluateParseTree(debugger->d.p, tree, &dvTemp.intValue, &dvTemp.segmentValue)) { dvTemp.type = CLIDV_ERROR_TYPE; } } @@ -1085,7 +1094,7 @@ bool CLIDebuggerRunCommand(struct CLIDebugger* debugger, const char* line, size_ return false; } -static void _commandLine(struct mDebugger* debugger) { +static void _commandLine(struct mDebuggerModule* debugger, int32_t timeoutMs) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; const char* line; size_t len; @@ -1094,14 +1103,19 @@ static void _commandLine(struct mDebugger* debugger) { } else { _printStatus(cliDebugger, 0); } - while (debugger->state == DEBUGGER_PAUSED) { - line = cliDebugger->backend->readline(cliDebugger->backend, &len); - if (!line || len == 0) { - debugger->state = DEBUGGER_SHUTDOWN; + while (debugger->isPaused && !mDebuggerIsShutdown(debugger->p)) { + int poll = cliDebugger->backend->poll(cliDebugger->backend, timeoutMs); + if (poll <= 0) { + if (poll < 0) { + mDebuggerShutdown(debugger->p); + } else { + cliDebugger->skipStatus = true; + } return; } - if (line[0] == '\033') { - cliDebugger->skipStatus = true; + line = cliDebugger->backend->readline(cliDebugger->backend, &len); + if (!line || len == 0) { + mDebuggerShutdown(debugger->p); return; } if (line[0] == '\n') { @@ -1120,7 +1134,7 @@ static void _commandLine(struct mDebugger* debugger) { } } -static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { +static void _reportEntry(struct mDebuggerModule* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; if (cliDebugger->traceRemaining > 0) { cliDebugger->traceRemaining = 0; @@ -1162,7 +1176,7 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r case DEBUGGER_ENTER_STACK: if (info) { if (info->type.st.traceType == STACK_TRACE_BREAK_ON_CALL) { - struct mStackTrace* stack = &cliDebugger->d.stackTrace; + struct mStackTrace* stack = &cliDebugger->d.p->stackTrace; struct mStackFrame* frame = mStackTraceGetFrame(stack, 0); if (frame->interrupt) { cliDebugger->backend->printf(cliDebugger->backend, "Hit interrupt at at 0x%08X\n", info->address); @@ -1180,7 +1194,7 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r } } -static void _cliDebuggerInit(struct mDebugger* debugger) { +static void _cliDebuggerInit(struct mDebuggerModule* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; cliDebugger->traceRemaining = 0; cliDebugger->traceVf = NULL; @@ -1191,7 +1205,7 @@ static void _cliDebuggerInit(struct mDebugger* debugger) { } } -static void _cliDebuggerDeinit(struct mDebugger* debugger) { +static void _cliDebuggerDeinit(struct mDebuggerModule* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; if (cliDebugger->traceVf) { cliDebugger->traceVf->close(cliDebugger->traceVf); @@ -1211,23 +1225,22 @@ static void _cliDebuggerDeinit(struct mDebugger* debugger) { } } -static void _cliDebuggerCustom(struct mDebugger* debugger) { +static void _cliDebuggerCustom(struct mDebuggerModule* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; - bool retain = true; - enum mDebuggerState next = DEBUGGER_RUNNING; if (cliDebugger->traceRemaining) { - retain = _doTrace(cliDebugger) && retain; - next = DEBUGGER_PAUSED; + if (!_doTrace(cliDebugger)) { + debugger->isPaused = true; + debugger->needsCallback = false; + } } - if (cliDebugger->system) { - retain = cliDebugger->system->custom(cliDebugger->system) && retain; - } - if (!retain && debugger->state == DEBUGGER_CALLBACK) { - debugger->state = next; + if (cliDebugger->system && cliDebugger->system->custom) { + debugger->needsCallback = cliDebugger->system->custom(cliDebugger->system) || debugger->needsCallback; } + + mDebuggerUpdatePaused(debugger->p); } -static void _cliDebuggerInterrupt(struct mDebugger* debugger) { +static void _cliDebuggerInterrupt(struct mDebuggerModule* debugger) { struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; if (cliDebugger->backend->interrupt) { cliDebugger->backend->interrupt(cliDebugger->backend); @@ -1323,13 +1336,13 @@ static void _backtrace(struct CLIDebugger* debugger, struct CLIDebugVector* dv) if (!CLIDebuggerCheckTraceMode(debugger, true)) { return; } - struct mStackTrace* stack = &debugger->d.stackTrace; + struct mStackTrace* stack = &debugger->d.p->stackTrace; ssize_t frames = mStackTraceGetDepth(stack); if (dv && dv->type == CLIDV_INT_TYPE && dv->intValue < frames) { frames = dv->intValue; } ssize_t i; - struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable; + struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable; for (i = 0; i < frames; ++i) { char trace[1024]; size_t traceSize = sizeof(trace) - 2; @@ -1343,7 +1356,7 @@ static void _finish(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { if (!CLIDebuggerCheckTraceMode(debugger, true)) { return; } - struct mStackTrace* stack = &debugger->d.stackTrace; + struct mStackTrace* stack = &debugger->d.p->stackTrace; struct mStackFrame* frame = mStackTraceGetFrame(stack, 0); if (!frame) { debugger->backend->printf(debugger->backend, "No current stack frame.\n"); @@ -1369,7 +1382,7 @@ static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVect debugger->backend->printf(debugger->backend, "%s\n", ERROR_INVALID_ARGS); return; } - struct mDebuggerPlatform* platform = debugger->d.platform; + struct mDebuggerPlatform* platform = debugger->d.p->platform; if (strcmp(dv->charValue, "off") == 0) { platform->setStackTraceMode(platform, STACK_TRACE_DISABLED); } else if (strcmp(dv->charValue, "trace-only") == 0) { @@ -1386,7 +1399,7 @@ static void _setStackTraceMode(struct CLIDebugger* debugger, struct CLIDebugVect } static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable; + struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable; if (!symbolTable) { debugger->backend->printf(debugger->backend, "No symbol table available.\n"); return; @@ -1420,7 +1433,7 @@ static void _loadSymbols(struct CLIDebugger* debugger, struct CLIDebugVector* dv } static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable; + struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable; if (!symbolTable) { debugger->backend->printf(debugger->backend, "No symbol table available.\n"); return; @@ -1437,7 +1450,7 @@ static void _setSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) } static void _findSymbol(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { - struct mDebuggerSymbols* symbolTable = debugger->d.core->symbolTable; + struct mDebuggerSymbols* symbolTable = debugger->d.p->core->symbolTable; if (!symbolTable) { debugger->backend->printf(debugger->backend, "No symbol table available.\n"); return; diff --git a/src/feature/editline/cli-el-backend.c b/src/debugger/cli-el-backend.c similarity index 55% rename from src/feature/editline/cli-el-backend.c rename to src/debugger/cli-el-backend.c index 30cb9399f..382a05c14 100644 --- a/src/feature/editline/cli-el-backend.c +++ b/src/debugger/cli-el-backend.c @@ -3,16 +3,35 @@ * 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 "cli-el-backend.h" +#include #include #include +#include #include #include +struct CLIDebuggerEditLineBackend { + struct CLIDebuggerBackend d; + + EditLine* elstate; + History* histate; + + int count; + const char* prompt; + bool doPrompt; + Thread promptThread; + Mutex promptMutex; + Condition promptRead; + Condition promptWrite; + bool exitThread; +}; + static struct CLIDebugger* _activeDebugger; +static THREAD_ENTRY _promptThread(void*); + static char* _prompt(EditLine* el) { UNUSED(el); return "> "; @@ -20,7 +39,10 @@ static char* _prompt(EditLine* el) { static void _breakIntoDefault(int signal) { UNUSED(signal); - mDebuggerEnter(&_activeDebugger->d, DEBUGGER_ENTER_MANUAL, 0); + struct mDebuggerEntryInfo info = { + .target = &_activeDebugger->d + }; + mDebuggerEnter(_activeDebugger->d.p, DEBUGGER_ENTER_MANUAL, &info); } static unsigned char _tabComplete(EditLine* elstate, int ch) { @@ -40,7 +62,7 @@ static unsigned char _tabComplete(EditLine* elstate, int ch) { } ATTRIBUTE_FORMAT(printf, 2, 3) -void _CLIDebuggerEditLinePrintf(struct CLIDebuggerBackend* be, const char* fmt, ...) { +static void CLIDebuggerEditLinePrintf(struct CLIDebuggerBackend* be, const char* fmt, ...) { UNUSED(be); va_list args; va_start(args, fmt); @@ -48,7 +70,7 @@ void _CLIDebuggerEditLinePrintf(struct CLIDebuggerBackend* be, const char* fmt, va_end(args); } -void _CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) { +static void CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) { struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; // TODO: get argv[0] elbe->elstate = el_init(binaryName, stdin, stdout, stderr); @@ -78,12 +100,26 @@ void _CLIDebuggerEditLineInit(struct CLIDebuggerBackend* be) { } } + MutexInit(&elbe->promptMutex); + ConditionInit(&elbe->promptRead); + ConditionInit(&elbe->promptWrite); + elbe->prompt = NULL; + elbe->exitThread = false; + elbe->doPrompt = false; + ThreadCreate(&elbe->promptThread, _promptThread, elbe); + _activeDebugger = be->p; signal(SIGINT, _breakIntoDefault); } -void _CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) { +static void CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) { struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; + MutexLock(&elbe->promptMutex); + elbe->exitThread = true; + ConditionWake(&elbe->promptWrite); + MutexUnlock(&elbe->promptMutex); + ThreadJoin(&elbe->promptThread); + char path[PATH_MAX + 1]; mCoreConfigDirectory(path, PATH_MAX); if (path[0]) { @@ -108,11 +144,52 @@ void _CLIDebuggerEditLineDeinit(struct CLIDebuggerBackend* be) { free(elbe); } -const char* _CLIDebuggerEditLineReadLine(struct CLIDebuggerBackend* be, size_t* len) { +static THREAD_ENTRY _promptThread(void* context) { + struct CLIDebuggerEditLineBackend* elbe = context; + + MutexLock(&elbe->promptMutex); + while (!elbe->exitThread) { + if (elbe->doPrompt) { + MutexUnlock(&elbe->promptMutex); + elbe->prompt = el_gets(elbe->elstate, &elbe->count); + MutexLock(&elbe->promptMutex); + elbe->doPrompt = false; + ConditionWake(&elbe->promptRead); + } + ConditionWait(&elbe->promptWrite, &elbe->promptMutex); + } + MutexUnlock(&elbe->promptMutex); + THREAD_EXIT(0); +} + +static int CLIDebuggerEditLinePoll(struct CLIDebuggerBackend* be, int32_t timeoutMs) { + struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; + int gotPrompt = 0; + MutexLock(&elbe->promptMutex); + if (!elbe->prompt) { + elbe->doPrompt = true; + ConditionWake(&elbe->promptWrite); + ConditionWaitTimed(&elbe->promptRead, &elbe->promptMutex, timeoutMs); + } + if (elbe->prompt) { + gotPrompt = 1; + } + MutexUnlock(&elbe->promptMutex); + + return gotPrompt; +} + +static const char* CLIDebuggerEditLineReadLine(struct CLIDebuggerBackend* be, size_t* len) { struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; - int count; *len = 0; - const char* line = el_gets(elbe->elstate, &count); + if (CLIDebuggerEditLinePoll(be, -1) != 1) { + return NULL; + } + MutexLock(&elbe->promptMutex); + int count = elbe->count; + const char* line = elbe->prompt; + elbe->prompt = NULL; + MutexUnlock(&elbe->promptMutex); if (line) { if (count > 1) { // Crop off newline @@ -123,12 +200,13 @@ const char* _CLIDebuggerEditLineReadLine(struct CLIDebuggerBackend* be, size_t* } return line; } -void _CLIDebuggerEditLineLineAppend(struct CLIDebuggerBackend* be, const char* line) { + +static void CLIDebuggerEditLineLineAppend(struct CLIDebuggerBackend* be, const char* line) { struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; el_insertstr(elbe->elstate, line); } -const char* _CLIDebuggerEditLineHistoryLast(struct CLIDebuggerBackend* be, size_t* len) { +static const char* CLIDebuggerEditLineHistoryLast(struct CLIDebuggerBackend* be, size_t* len) { struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; HistEvent ev; if (history(elbe->histate, &ev, H_FIRST) < 0) { @@ -145,7 +223,7 @@ const char* _CLIDebuggerEditLineHistoryLast(struct CLIDebuggerBackend* be, size_ return ev.str; } -void _CLIDebuggerEditLineHistoryAppend(struct CLIDebuggerBackend* be, const char* line) { +static void CLIDebuggerEditLineHistoryAppend(struct CLIDebuggerBackend* be, const char* line) { struct CLIDebuggerEditLineBackend* elbe = (struct CLIDebuggerEditLineBackend*) be; HistEvent ev; history(elbe->histate, &ev, H_ENTER, line); @@ -153,13 +231,14 @@ void _CLIDebuggerEditLineHistoryAppend(struct CLIDebuggerBackend* be, const char struct CLIDebuggerBackend* CLIDebuggerEditLineBackendCreate(void) { struct CLIDebuggerEditLineBackend* elbe = calloc(1, sizeof(*elbe)); - elbe->d.printf = _CLIDebuggerEditLinePrintf; - elbe->d.init = _CLIDebuggerEditLineInit; - elbe->d.deinit = _CLIDebuggerEditLineDeinit; - elbe->d.readline = _CLIDebuggerEditLineReadLine; - elbe->d.lineAppend = _CLIDebuggerEditLineLineAppend; - elbe->d.historyLast = _CLIDebuggerEditLineHistoryLast; - elbe->d.historyAppend = _CLIDebuggerEditLineHistoryAppend; + elbe->d.printf = CLIDebuggerEditLinePrintf; + elbe->d.init = CLIDebuggerEditLineInit; + elbe->d.deinit = CLIDebuggerEditLineDeinit; + elbe->d.poll = CLIDebuggerEditLinePoll; + elbe->d.readline = CLIDebuggerEditLineReadLine; + elbe->d.lineAppend = CLIDebuggerEditLineLineAppend; + elbe->d.historyLast = CLIDebuggerEditLineHistoryLast; + elbe->d.historyAppend = CLIDebuggerEditLineHistoryAppend; elbe->d.interrupt = NULL; return &elbe->d; } diff --git a/src/debugger/debugger.c b/src/debugger/debugger.c index cc6beab9c..7de4772d7 100644 --- a/src/debugger/debugger.c +++ b/src/debugger/debugger.c @@ -24,17 +24,18 @@ mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger"); DEFINE_VECTOR(mBreakpointList, struct mBreakpoint); DEFINE_VECTOR(mWatchpointList, struct mWatchpoint); +DEFINE_VECTOR(mDebuggerModuleList, struct mDebuggerModule*); -static void mDebuggerInit(void* cpu, struct mCPUComponent* component); -static void mDebuggerDeinit(struct mCPUComponent* component); +static void _mDebuggerInit(void* cpu, struct mCPUComponent* component); +static void _mDebuggerDeinit(struct mCPUComponent* component); -struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) { +struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mCore* core) { if (!core->supportsDebuggerType(core, type)) { return NULL; } union DebugUnion { - struct mDebugger d; + struct mDebuggerModule d; struct CLIDebugger cli; #ifdef USE_GDB_STUB struct GDBStub gdb; @@ -53,24 +54,40 @@ struct mDebugger* mDebuggerCreate(enum mDebuggerType type, struct mCore* core) { case DEBUGGER_GDB: #ifdef USE_GDB_STUB GDBStubCreate(&debugger->gdb); - GDBStubListen(&debugger->gdb, 2345, 0, GDB_WATCHPOINT_STANDARD_LOGIC); + struct Address localHost = { + .version = IPV4, + .ipv4 = 0x7F000001 + }; + GDBStubListen(&debugger->gdb, 2345, &localHost, GDB_WATCHPOINT_STANDARD_LOGIC); break; #endif case DEBUGGER_NONE: + case DEBUGGER_ACCESS_LOGGER: case DEBUGGER_CUSTOM: case DEBUGGER_MAX: free(debugger); - return 0; + return NULL; break; } return &debugger->d; } +void mDebuggerInit(struct mDebugger* debugger) { + memset(debugger, 0, sizeof(*debugger)); + mDebuggerModuleListInit(&debugger->modules, 4); + TableInit(&debugger->pointOwner, 0, NULL); +} + +void mDebuggerDeinit(struct mDebugger* debugger) { + mDebuggerModuleListDeinit(&debugger->modules); + TableDeinit(&debugger->pointOwner); +} + void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) { debugger->d.id = DEBUGGER_ID; - debugger->d.init = mDebuggerInit; - debugger->d.deinit = mDebuggerDeinit; + debugger->d.init = _mDebuggerInit; + debugger->d.deinit = _mDebuggerDeinit; debugger->core = core; if (!debugger->core->symbolTable) { debugger->core->loadSymbols(debugger->core, NULL); @@ -80,7 +97,36 @@ void mDebuggerAttach(struct mDebugger* debugger, struct mCore* core) { core->attachDebugger(core, debugger); } -void mDebuggerRun(struct mDebugger* debugger) { +void mDebuggerAttachModule(struct mDebugger* debugger, struct mDebuggerModule* module) { + module->p = debugger; + *mDebuggerModuleListAppend(&debugger->modules) = module; + if (debugger->state > DEBUGGER_CREATED && debugger->state < DEBUGGER_SHUTDOWN) { + if (module->init) { + module->init(module); + } + } +} + +void mDebuggerDetachModule(struct mDebugger* debugger, struct mDebuggerModule* module) { + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + if (module != *mDebuggerModuleListGetPointer(&debugger->modules, i)) { + continue; + } + if (debugger->state > DEBUGGER_CREATED && debugger->state < DEBUGGER_SHUTDOWN) { + if (module->deinit) { + module->deinit(module); + } + } + mDebuggerModuleListShift(&debugger->modules, i, 1); + break; + } +} + +void mDebuggerRunTimeout(struct mDebugger* debugger, int32_t timeoutMs) { + size_t i; + size_t anyPaused = 0; + switch (debugger->state) { case DEBUGGER_RUNNING: if (!debugger->platform->hasBreakpoints(debugger->platform)) { @@ -93,20 +139,43 @@ void mDebuggerRun(struct mDebugger* debugger) { case DEBUGGER_CALLBACK: debugger->core->step(debugger->core); debugger->platform->checkBreakpoints(debugger->platform); - debugger->custom(debugger); + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->needsCallback) { + module->custom(module); + } + } break; case DEBUGGER_PAUSED: - if (debugger->paused) { - debugger->paused(debugger); - } else { + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->isPaused) { + if (module->paused) { + module->paused(module, timeoutMs); + } + if (module->isPaused) { + ++anyPaused; + } + } else if (module->needsCallback) { + module->custom(module); + } + } + if (debugger->state == DEBUGGER_PAUSED && !anyPaused) { debugger->state = DEBUGGER_RUNNING; } break; + case DEBUGGER_CREATED: + mLOG(DEBUGGER, ERROR, "Attempted to run debugger before initializtion"); + return; case DEBUGGER_SHUTDOWN: return; } } +void mDebuggerRun(struct mDebugger* debugger) { + mDebuggerRunTimeout(debugger, 50); +} + void mDebuggerRunFrame(struct mDebugger* debugger) { uint32_t frame = debugger->core->frameCounter(debugger->core); do { @@ -115,30 +184,115 @@ void mDebuggerRunFrame(struct mDebugger* debugger) { } void mDebuggerEnter(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { - debugger->state = DEBUGGER_PAUSED; if (debugger->platform->entered) { debugger->platform->entered(debugger->platform, reason, info); } + + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (info && info->target) { + // This check needs to be in the loop to make sure we don't + // accidentally enter a module that isn't registered. + // This is an error by the caller, but it's good to check for. + if (info->target != module) { + continue; + } + // Make this the last loop so we don't hit this one twice + i = mDebuggerModuleListSize(&debugger->modules) - 1; + } + module->isPaused = true; + if (module->entered) { + module->entered(module, reason, info); + } + } + #ifdef ENABLE_SCRIPTING if (debugger->bridge) { mScriptBridgeDebuggerEntered(debugger->bridge, reason, info); } #endif + + mDebuggerUpdatePaused(debugger); } -static void mDebuggerInit(void* cpu, struct mCPUComponent* component) { - struct mDebugger* debugger = (struct mDebugger*) component; - debugger->state = DEBUGGER_RUNNING; - debugger->platform->init(cpu, debugger->platform); - if (debugger->init) { - debugger->init(debugger); +void mDebuggerInterrupt(struct mDebugger* debugger) { + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->interrupt) { + module->interrupt(module); + } } } -static void mDebuggerDeinit(struct mCPUComponent* component) { +void mDebuggerUpdatePaused(struct mDebugger* debugger) { + if (debugger->state == DEBUGGER_SHUTDOWN) { + return; + } + + size_t anyPaused = 0; + size_t anyCallback = 0; + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->isPaused) { + ++anyPaused; + } + if (module->needsCallback) { + ++anyCallback; + } + } + if (anyPaused) { + debugger->state = DEBUGGER_PAUSED; + } else if (anyCallback) { + debugger->state = DEBUGGER_CALLBACK; + } else { + debugger->state = DEBUGGER_RUNNING; + } +} + +void mDebuggerShutdown(struct mDebugger* debugger) { + debugger->state = DEBUGGER_SHUTDOWN; +} + +bool mDebuggerIsShutdown(const struct mDebugger* debugger) { + return debugger->state == DEBUGGER_SHUTDOWN; +} + +void mDebuggerUpdate(struct mDebugger* debugger) { + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->update) { + module->update(module); + } + } +} + +static void _mDebuggerInit(void* cpu, struct mCPUComponent* component) { struct mDebugger* debugger = (struct mDebugger*) component; - if (debugger->deinit) { - debugger->deinit(debugger); + debugger->state = DEBUGGER_RUNNING; + debugger->platform->init(cpu, debugger->platform); + + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->init) { + module->init(module); + } + } +} + +static void _mDebuggerDeinit(struct mCPUComponent* component) { + struct mDebugger* debugger = (struct mDebugger*) component; + debugger->state = DEBUGGER_SHUTDOWN; + size_t i; + for (i = 0; i < mDebuggerModuleListSize(&debugger->modules); ++i) { + struct mDebuggerModule* module = *mDebuggerModuleListGetPointer(&debugger->modules, i); + if (module->deinit) { + module->deinit(module); + } } debugger->platform->deinit(debugger->platform); } @@ -161,3 +315,8 @@ bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int } return false; } + +void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule* debugger) { + debugger->needsCallback = true; + mDebuggerUpdatePaused(debugger->p); +} diff --git a/src/debugger/gdb-stub.c b/src/debugger/gdb-stub.c index ca8c0d1ec..86e28d997 100644 --- a/src/debugger/gdb-stub.c +++ b/src/debugger/gdb-stub.c @@ -17,8 +17,6 @@ #define SIGTRAP 5 /* Win32 Signals do not include SIGTRAP */ #endif -#define SOCKET_TIMEOUT 50 - enum GDBError { GDB_NO_ERROR = 0x00, GDB_BAD_ARGUMENTS = 0x06, @@ -50,20 +48,30 @@ static const char* TARGET_XML = "" "" "" "" - "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" "" ""; static void _sendMessage(struct GDBStub* stub); -static void _gdbStubDeinit(struct mDebugger* debugger) { +static void _gdbStubDeinit(struct mDebuggerModule* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; if (!SOCKET_FAILED(stub->socket)) { GDBStubShutdown(stub); } } -static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { +static void _gdbStubEntered(struct mDebuggerModule* debugger, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { struct GDBStub* stub = (struct GDBStub*) debugger; switch (reason) { case DEBUGGER_ENTER_MANUAL: @@ -118,27 +126,24 @@ static void _gdbStubEntered(struct mDebugger* debugger, enum mDebuggerEntryReaso _sendMessage(stub); } -static void _gdbStubPoll(struct mDebugger* debugger) { +static void _gdbStubPoll(struct mDebuggerModule* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; --stub->untilPoll; if (stub->untilPoll > 0) { return; } stub->untilPoll = GDB_STUB_INTERVAL; - stub->shouldBlock = false; - GDBStubUpdate(stub); + GDBStubUpdate(stub, 0); } -static void _gdbStubWait(struct mDebugger* debugger) { +static void _gdbStubWait(struct mDebuggerModule* debugger, int32_t timeoutMs) { struct GDBStub* stub = (struct GDBStub*) debugger; - stub->shouldBlock = true; - GDBStubUpdate(stub); + GDBStubUpdate(stub, timeoutMs); } -static void _gdbStubUpdate(struct mDebugger* debugger) { +static void _gdbStubUpdate(struct mDebuggerModule* debugger) { struct GDBStub* stub = (struct GDBStub*) debugger; - stub->shouldBlock = false; - GDBStubUpdate(stub); + GDBStubUpdate(stub, 0); } static void _ack(struct GDBStub* stub) { @@ -242,14 +247,15 @@ static void _writeHostInfo(struct GDBStub* stub) { } static void _continue(struct GDBStub* stub, const char* message) { - stub->d.state = DEBUGGER_CALLBACK; stub->untilPoll = GDB_STUB_INTERVAL; + stub->d.isPaused = false; + mDebuggerModuleSetNeedsCallback(&stub->d); // TODO: parse message UNUSED(message); } static void _step(struct GDBStub* stub, const char* message) { - stub->d.core->step(stub->d.core); + stub->d.p->core->step(stub->d.p->core); snprintf(stub->outgoing, GDB_STUB_MAX_LINE - 4, "S%02x", SIGTRAP); _sendMessage(stub); // TODO: parse message @@ -271,7 +277,7 @@ static void _writeMemoryBinary(struct GDBStub* stub, const char* message) { return; } - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; for (i = 0; i < size; i++) { uint8_t byte = *readAddress; ++readAddress; @@ -305,7 +311,7 @@ static void _writeMemory(struct GDBStub* stub, const char* message) { return; } - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; for (i = 0; i < size; ++i, readAddress += 2) { uint8_t byte = _hex2int(readAddress, 2); GBAPatch8(cpu, address + i, byte, 0); @@ -325,7 +331,7 @@ static void _readMemory(struct GDBStub* stub, const char* message) { _error(stub, GDB_BAD_ARGUMENTS); return; } - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; int writeAddress = 0; for (i = 0; i < size; ++i, writeAddress += 2) { uint8_t byte = cpu->memory.load8(cpu, address + i, 0); @@ -336,7 +342,7 @@ static void _readMemory(struct GDBStub* stub, const char* message) { } static void _writeGPRs(struct GDBStub* stub, const char* message) { - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; const char* readAddress = message; int r; @@ -354,8 +360,12 @@ static void _writeGPRs(struct GDBStub* stub, const char* message) { _sendMessage(stub); } +static int32_t _readPC(struct ARMCore* cpu) { + return cpu->gprs[ARM_PC] - (cpu->cpsr.t ? WORD_SIZE_THUMB : WORD_SIZE_ARM); +} + static void _readGPRs(struct GDBStub* stub, const char* message) { - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; UNUSED(message); int r; int i = 0; @@ -367,7 +377,7 @@ static void _readGPRs(struct GDBStub* stub, const char* message) { } // Program counter - _int2hex32(cpu->gprs[ARM_PC] - (cpu->cpsr.t ? WORD_SIZE_THUMB : WORD_SIZE_ARM), &stub->outgoing[i]); + _int2hex32(_readPC(cpu), &stub->outgoing[i]); i += 8; // CPU status @@ -379,7 +389,7 @@ static void _readGPRs(struct GDBStub* stub, const char* message) { } static void _writeRegister(struct GDBStub* stub, const char* message) { - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; const char* readAddress = message; unsigned i = 0; @@ -412,13 +422,15 @@ static void _writeRegister(struct GDBStub* stub, const char* message) { } static void _readRegister(struct GDBStub* stub, const char* message) { - struct ARMCore* cpu = stub->d.core->cpu; + struct ARMCore* cpu = stub->d.p->core->cpu; const char* readAddress = message; unsigned i = 0; uint32_t reg = _readHex(readAddress, &i); uint32_t value; - if (reg < 0x10) { + if (reg < ARM_PC) { value = cpu->gprs[reg]; + } else if (reg == ARM_PC) { + value = _readPC(cpu); } else if (reg == 0x19) { value = cpu->cpsr.packed; } else { @@ -457,7 +469,7 @@ static void _processQSupportedCommand(struct GDBStub* stub, const char* message) } message = end + 1; } - strncpy(stub->outgoing, "swbreak+;hwbreak+;qXfer:features:read+;qXfer:memory-map:read+", GDB_STUB_MAX_LINE - 4); + strncpy(stub->outgoing, "swbreak+;hwbreak+;qXfer:features:read+;qXfer:memory-map:read+;QStartNoAckMode+", GDB_STUB_MAX_LINE - 4); } static void _processQXferCommand(struct GDBStub* stub, const char* params, const char* data) { @@ -497,7 +509,7 @@ static void _generateMemoryMapXml(struct GDBStub* stub, char* memoryMap) { strncpy(memoryMap, "", 27); index += strlen(memoryMap); const struct mCoreMemoryBlock* blocks; - size_t nBlocks = stub->d.core->listMemoryBlocks(stub->d.core, &blocks); + size_t nBlocks = stub->d.p->core->listMemoryBlocks(stub->d.p->core, &blocks); size_t i; for (i = 0; i < nBlocks; ++i) { if (!(blocks[i].flags & mCORE_MEMORY_MAPPED)) { @@ -542,7 +554,7 @@ static void _processQReadCommand(struct GDBStub* stub, const char* message) { static void _processQWriteCommand(struct GDBStub* stub, const char* message) { stub->outgoing[0] = '\0'; - if (!strncmp("StartNoAckMode#", message, 16)) { + if (!strncmp("StartNoAckMode#", message, 15)) { stub->lineAck = GDB_ACK_OFF; strncpy(stub->outgoing, "OK", GDB_STUB_MAX_LINE - 4); } @@ -559,7 +571,11 @@ static void _processVReadCommand(struct GDBStub* stub, const char* message) { stub->outgoing[0] = '\0'; if (!strncmp("Attach", message, 6)) { strncpy(stub->outgoing, "1", GDB_STUB_MAX_LINE - 4); - mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); + stub->d.isPaused = true; + struct mDebuggerEntryInfo info = { + .target = &stub->d + }; + mDebuggerEnter(stub->d.p, DEBUGGER_ENTER_MANUAL, &info); } _sendMessage(stub); } @@ -582,19 +598,19 @@ static void _setBreakpoint(struct GDBStub* stub, const char* message) { switch (message[0]) { case '0': case '1': - stub->d.platform->setBreakpoint(stub->d.platform, &breakpoint); + stub->d.p->platform->setBreakpoint(stub->d.p->platform, &stub->d, &breakpoint); break; case '2': watchpoint.type = stub->watchpointsBehavior == GDB_WATCHPOINT_OVERRIDE_LOGIC_ANY_WRITE ? WATCHPOINT_WRITE : WATCHPOINT_WRITE_CHANGE; - stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint); + stub->d.p->platform->setWatchpoint(stub->d.p->platform, &stub->d, &watchpoint); break; case '3': watchpoint.type = WATCHPOINT_READ; - stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint); + stub->d.p->platform->setWatchpoint(stub->d.p->platform, &stub->d, &watchpoint); break; case '4': watchpoint.type = WATCHPOINT_RW; - stub->d.platform->setWatchpoint(stub->d.platform, &watchpoint); + stub->d.p->platform->setWatchpoint(stub->d.p->platform, &stub->d, &watchpoint); break; default: stub->outgoing[0] = '\0'; @@ -617,12 +633,12 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) { case '0': case '1': mBreakpointListInit(&breakpoints, 0); - stub->d.platform->listBreakpoints(stub->d.platform, &breakpoints); + stub->d.p->platform->listBreakpoints(stub->d.p->platform, &stub->d, &breakpoints); for (index = 0; index < mBreakpointListSize(&breakpoints); ++index) { if (mBreakpointListGetPointer(&breakpoints, index)->address != address) { continue; } - stub->d.platform->clearBreakpoint(stub->d.platform, mBreakpointListGetPointer(&breakpoints, index)->id); + stub->d.p->platform->clearBreakpoint(stub->d.p->platform, mBreakpointListGetPointer(&breakpoints, index)->id); } mBreakpointListDeinit(&breakpoints); break; @@ -630,13 +646,13 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) { case '3': case '4': mWatchpointListInit(&watchpoints, 0); - stub->d.platform->listWatchpoints(stub->d.platform, &watchpoints); + stub->d.p->platform->listWatchpoints(stub->d.p->platform, &stub->d, &watchpoints); for (index = 0; index < mWatchpointListSize(&watchpoints); ++index) { struct mWatchpoint* watchpoint = mWatchpointListGetPointer(&watchpoints, index); if (address >= watchpoint->minAddress && address < watchpoint->maxAddress) { continue; } - stub->d.platform->clearBreakpoint(stub->d.platform, watchpoint->id); + stub->d.p->platform->clearBreakpoint(stub->d.p->platform, watchpoint->id); } mWatchpointListDeinit(&watchpoints); break; @@ -650,6 +666,9 @@ static void _clearBreakpoint(struct GDBStub* stub, const char* message) { size_t _parseGDBMessage(struct GDBStub* stub, const char* message) { uint8_t checksum = 0; int parsed = 1; + struct mDebuggerEntryInfo info = { + .target = &stub->d + }; switch (*message) { case '+': stub->lineAck = GDB_ACK_RECEIVED; @@ -661,7 +680,8 @@ size_t _parseGDBMessage(struct GDBStub* stub, const char* message) { ++message; break; case '\x03': - mDebuggerEnter(&stub->d, DEBUGGER_ENTER_MANUAL, 0); + stub->d.isPaused = true; + mDebuggerEnter(stub->d.p, DEBUGGER_ENTER_MANUAL, &info); return parsed; default: _nak(stub); @@ -773,7 +793,6 @@ void GDBStubCreate(struct GDBStub* stub) { stub->d.type = DEBUGGER_GDB; stub->untilPoll = GDB_STUB_INTERVAL; stub->lineAck = GDB_ACK_PENDING; - stub->shouldBlock = false; } bool GDBStubListen(struct GDBStub* stub, int port, const struct Address* bindAddress, enum GDBWatchpointsBehvaior watchpointsBehavior) { @@ -810,9 +829,9 @@ void GDBStubHangup(struct GDBStub* stub) { SocketClose(stub->connection); stub->connection = INVALID_SOCKET; } - if (stub->d.state == DEBUGGER_PAUSED) { - stub->d.state = DEBUGGER_RUNNING; - } + stub->d.needsCallback = false; + stub->d.isPaused = false; + mDebuggerUpdatePaused(stub->d.p); } void GDBStubShutdown(struct GDBStub* stub) { @@ -823,54 +842,57 @@ void GDBStubShutdown(struct GDBStub* stub) { } } -void GDBStubUpdate(struct GDBStub* stub) { +bool GDBStubUpdate(struct GDBStub* stub, int32_t timeoutMs) { if (stub->socket == INVALID_SOCKET) { - if (stub->d.state == DEBUGGER_PAUSED) { - stub->d.state = DEBUGGER_RUNNING; - } - return; + stub->d.needsCallback = false; + stub->d.isPaused = false; + mDebuggerUpdatePaused(stub->d.p); + return false; } if (stub->connection == INVALID_SOCKET) { - if (stub->shouldBlock) { + if (timeoutMs) { Socket reads = stub->socket; - SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT); + SocketPoll(1, &reads, 0, 0, timeoutMs); } stub->connection = SocketAccept(stub->socket, 0); if (!SOCKET_FAILED(stub->connection)) { if (!SocketSetBlocking(stub->connection, false)) { goto connectionLost; } - mDebuggerEnter(&stub->d, DEBUGGER_ENTER_ATTACHED, 0); + mDebuggerEnter(stub->d.p, DEBUGGER_ENTER_ATTACHED, 0); } else if (SocketWouldBlock()) { - return; + return false; } else { goto connectionLost; } + SocketSetTCPPush(stub->connection, 1); } - while (true) { - if (stub->shouldBlock) { - Socket reads = stub->connection; - SocketPoll(1, &reads, 0, 0, SOCKET_TIMEOUT); - } - ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1); - if (messageLen == 0) { - goto connectionLost; - } - if (messageLen == -1) { - if (SocketWouldBlock()) { - return; - } - goto connectionLost; - } - stub->line[messageLen] = '\0'; - mLOG(DEBUGGER, DEBUG, "< %s", stub->line); - ssize_t position = 0; - while (position < messageLen) { - position += _parseGDBMessage(stub, &stub->line[position]); - } + + if (timeoutMs) { + Socket reads = stub->connection; + SocketPoll(1, &reads, 0, 0, timeoutMs); } + ssize_t messageLen = SocketRecv(stub->connection, stub->line, GDB_STUB_MAX_LINE - 1); + if (messageLen == 0) { + goto connectionLost; + } + if (messageLen == -1) { + if (SocketWouldBlock()) { + return false; + } + goto connectionLost; + } + + stub->line[messageLen] = '\0'; + mLOG(DEBUGGER, DEBUG, "< %s", stub->line); + ssize_t position = 0; + while (position < messageLen) { + position += _parseGDBMessage(stub, &stub->line[position]); + } + return true; connectionLost: mLOG(DEBUGGER, WARN, "Connection lost"); GDBStubHangup(stub); + return false; } diff --git a/src/debugger/parser.c b/src/debugger/parser.c index 0d4924ea9..3c3b037fa 100644 --- a/src/debugger/parser.c +++ b/src/debugger/parser.c @@ -11,8 +11,6 @@ DEFINE_VECTOR(LexVector, struct Token); -DEFINE_VECTOR(IntList, int32_t); - enum LexState { LEX_ERROR = -1, LEX_ROOT = 0, diff --git a/src/feature/CMakeLists.txt b/src/feature/CMakeLists.txt index ffb469953..b692338f4 100644 --- a/src/feature/CMakeLists.txt +++ b/src/feature/CMakeLists.txt @@ -1,8 +1,10 @@ include(ExportDirectory) set(SOURCE_FILES commandline.c + proxy-backend.c thread-proxy.c updater.c + video-backend.c video-logger.c) set(GUI_FILES diff --git a/src/feature/commandline.c b/src/feature/commandline.c index 72e5f6c26..7e720886d 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -5,9 +5,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include +#include #include #include +#include + +#ifdef USE_GDB_STUB +#include +#endif +#ifdef USE_EDITLINE +#include +#endif #include #ifdef _MSC_VER @@ -137,18 +147,14 @@ bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struc break; #ifdef USE_EDITLINE case 'd': - if (args->debuggerType != DEBUGGER_NONE) { - return false; - } - args->debuggerType = DEBUGGER_CLI; + args->debugAtStart = true; + args->debugCli = true; break; #endif #ifdef USE_GDB_STUB case 'g': - if (args->debuggerType != DEBUGGER_NONE) { - return false; - } - args->debuggerType = DEBUGGER_GDB; + args->debugAtStart = true; + args->debugGdb = true; break; #endif case 'h': @@ -210,6 +216,58 @@ void mArgumentsApply(const struct mArguments* args, struct mSubParser* subparser } } +bool mArgumentsApplyDebugger(const struct mArguments* args, struct mCore* core, struct mDebugger* debugger) { + bool hasDebugger = false; + + #ifdef USE_EDITLINE + if (args->debugCli) { + struct mDebuggerModule* module = mDebuggerCreateModule(DEBUGGER_CLI, core); + if (module) { + struct CLIDebugger* cliDebugger = (struct CLIDebugger*) module; + CLIDebuggerAttachBackend(cliDebugger, CLIDebuggerEditLineBackendCreate()); + mDebuggerAttachModule(debugger, module); + hasDebugger = true; + } + } +#endif + +#ifdef USE_GDB_STUB + if (args->debugGdb) { + struct mDebuggerModule* module = mDebuggerCreateModule(DEBUGGER_GDB, core); + if (module) { + mDebuggerAttachModule(debugger, module); + hasDebugger = true; + } + } +#endif + + return hasDebugger; +} + +void mArgumentsApplyFileLoads(const struct mArguments* args, struct mCore* core) { + if (args->patch) { + struct VFile* patch = VFileOpen(args->patch, O_RDONLY); + if (patch) { + core->loadPatch(core, patch); + patch->close(patch); + } + } else { + mCoreAutoloadPatch(core); + } + + struct mCheatDevice* device = NULL; + if (args->cheatsFile && (device = core->cheatDevice(core))) { + struct VFile* vf = VFileOpen(args->cheatsFile, O_RDONLY); + if (vf) { + mCheatDeviceClear(device); + mCheatParseFile(device, vf); + vf->close(vf); + } + } else { + mCoreAutoloadCheats(core); + } +} + void mArgumentsDeinit(struct mArguments* args) { free(args->fname); args->fname = 0; diff --git a/src/feature/ffmpeg/ffmpeg-common.h b/src/feature/ffmpeg/ffmpeg-common.h index 0f94cfbeb..299d5167d 100644 --- a/src/feature/ffmpeg/ffmpeg-common.h +++ b/src/feature/ffmpeg/ffmpeg-common.h @@ -34,6 +34,10 @@ CXX_GUARD_START #define FFMPEG_USE_PACKET_UNREF #endif +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 0) +#define FFMPEG_USE_NEW_CH_LAYOUT +#endif + static inline enum AVPixelFormat mColorFormatToFFmpegPixFmt(enum mColorFormat format) { switch (format) { #ifndef USE_LIBAV diff --git a/src/feature/ffmpeg/ffmpeg-encoder.c b/src/feature/ffmpeg/ffmpeg-encoder.c index f1a26ec32..220ce4d86 100644 --- a/src/feature/ffmpeg/ffmpeg-encoder.c +++ b/src/feature/ffmpeg/ffmpeg-encoder.c @@ -62,13 +62,13 @@ void FFmpegEncoderInit(struct FFmpegEncoder* encoder) { encoder->audioCodec = NULL; encoder->videoCodec = NULL; encoder->containerFormat = NULL; + encoder->isampleRate = PREFERRED_SAMPLE_RATE; FFmpegEncoderSetAudio(encoder, "flac", 0); FFmpegEncoderSetVideo(encoder, "libx264", 0, 0); FFmpegEncoderSetContainer(encoder, "matroska"); FFmpegEncoderSetDimensions(encoder, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); encoder->iwidth = GBA_VIDEO_HORIZONTAL_PIXELS; encoder->iheight = GBA_VIDEO_VERTICAL_PIXELS; - encoder->isampleRate = PREFERRED_SAMPLE_RATE; encoder->frameskip = 1; encoder->skipResidue = 0; encoder->loop = false; @@ -154,19 +154,35 @@ bool FFmpegEncoderSetAudio(struct FFmpegEncoder* encoder, const char* acodec, un } encoder->sampleRate = encoder->isampleRate; if (codec->supported_samplerates) { + bool gotSampleRate = false; + int highestSampleRate = 0; for (i = 0; codec->supported_samplerates[i]; ++i) { + if (codec->supported_samplerates[i] > highestSampleRate) { + highestSampleRate = codec->supported_samplerates[i]; + } if (codec->supported_samplerates[i] < encoder->isampleRate) { continue; } - if (encoder->sampleRate == encoder->isampleRate || encoder->sampleRate > codec->supported_samplerates[i]) { + if (!gotSampleRate || encoder->sampleRate > codec->supported_samplerates[i]) { encoder->sampleRate = codec->supported_samplerates[i]; + gotSampleRate = true; } } + if (!gotSampleRate) { + // There are no available sample rates that are higher than the input sample rate + // Let's use the highest available instead + encoder->sampleRate = highestSampleRate; + } } else if (codec->id == AV_CODEC_ID_FLAC) { // HACK: FLAC doesn't support > 65535Hz unless it's divisible by 10 if (encoder->sampleRate >= 65535) { encoder->sampleRate -= encoder->isampleRate % 10; } + } else if (codec->id == AV_CODEC_ID_VORBIS) { + // HACK: FLAC doesn't support > 48000Hz but doesn't tell us + if (encoder->sampleRate > 48000) { + encoder->sampleRate = 48000; + } } else if (codec->id == AV_CODEC_ID_AAC) { // HACK: AAC doesn't support 32768Hz (it rounds to 32000), but libfaac doesn't tell us that encoder->sampleRate = 48000; @@ -304,8 +320,12 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->audio = encoder->audioStream->codec; #endif encoder->audio->bit_rate = encoder->audioBitrate; +#ifdef FFMPEG_USE_NEW_CH_LAYOUT + av_channel_layout_copy(&encoder->audio->ch_layout, &(AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO); +#else encoder->audio->channels = 2; encoder->audio->channel_layout = AV_CH_LAYOUT_STEREO; +#endif encoder->audio->sample_rate = encoder->sampleRate; encoder->audio->sample_fmt = encoder->sampleFormat; AVDictionary* opts = 0; @@ -330,7 +350,11 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->audioFrame->nb_samples = encoder->audio->frame_size; encoder->audioFrame->format = encoder->audio->sample_fmt; encoder->audioFrame->pts = 0; +#ifdef FFMPEG_USE_NEW_CH_LAYOUT + av_channel_layout_copy(&encoder->audioFrame->ch_layout, &(AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO); +#else encoder->audioFrame->channel_layout = AV_CH_LAYOUT_STEREO; +#endif _ffmpegOpenResampleContext(encoder); av_frame_get_buffer(encoder->audioFrame, 0); @@ -881,7 +905,7 @@ void FFmpegEncoderSetInputSampleRate(struct FFmpegEncoder* encoder, int sampleRa } void _ffmpegOpenResampleContext(struct FFmpegEncoder* encoder) { - encoder->audioBufferSize = av_rescale_q(encoder->audioFrame->nb_samples, (AVRational) { 4, encoder->sampleRate }, (AVRational) { 1, encoder->isampleRate }); + encoder->audioBufferSize = av_rescale_q(encoder->audioFrame->nb_samples, (AVRational) { 1, encoder->sampleRate }, (AVRational) { 1, encoder->isampleRate }) * 4; encoder->audioBuffer = av_malloc(encoder->audioBufferSize); #ifdef USE_LIBAVRESAMPLE encoder->resampleContext = avresample_alloc_context(); @@ -892,9 +916,14 @@ void _ffmpegOpenResampleContext(struct FFmpegEncoder* encoder) { av_opt_set_int(encoder->resampleContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(encoder->resampleContext, "out_sample_fmt", encoder->sampleFormat, 0); avresample_open(encoder->resampleContext); +#else +#ifdef FFMPEG_USE_NEW_CH_LAYOUT + swr_alloc_set_opts2(&encoder->resampleContext, &(AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO, encoder->sampleFormat, encoder->sampleRate, + &(AVChannelLayout) AV_CHANNEL_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, encoder->isampleRate, 0, NULL); #else encoder->resampleContext = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, encoder->sampleFormat, encoder->sampleRate, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, encoder->isampleRate, 0, NULL); +#endif swr_init(encoder->resampleContext); #endif } diff --git a/src/feature/gui/cheats.c b/src/feature/gui/cheats.c index fda129a5b..9c3199631 100644 --- a/src/feature/gui/cheats.c +++ b/src/feature/gui/cheats.c @@ -9,6 +9,7 @@ #include #include "feature/gui/gui-runner.h" #include +#include enum mGUICheatAction { CHEAT_BACK = 0, diff --git a/src/feature/gui/gui-config.c b/src/feature/gui/gui-config.c index 8ab4dd7dc..4a6c79871 100644 --- a/src/feature/gui/gui-config.c +++ b/src/feature/gui/gui-config.c @@ -31,7 +31,7 @@ static bool _biosNamed(const char* name) { char ext[PATH_MAX + 1] = {}; separatePath(name, NULL, NULL, ext); - if (strstr(name, "bios")) { + if (strcasestr(name, "bios")) { return true; } if (!strncmp(ext, "bin", PATH_MAX)) { diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index 2e837891f..8c25a79fb 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #ifdef PSP2 @@ -123,34 +123,39 @@ static void _drawState(struct GUIBackground* background, void* id) { struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background; unsigned stateId = ((uint32_t) id) >> 16; if (gbaBackground->p->drawScreenshot) { - unsigned w, h; - gbaBackground->p->core->desiredVideoDimensions(gbaBackground->p->core, &w, &h); - size_t size = w * h * BYTES_PER_PIXEL; - if (size != gbaBackground->imageSize) { - mappedMemoryFree(gbaBackground->image, gbaBackground->imageSize); - gbaBackground->image = NULL; - } - if (gbaBackground->image && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) { - gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->image, w, h, true); + color_t* pixels = gbaBackground->image; + if (pixels && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) { + gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, gbaBackground->w, gbaBackground->h, true); return; } else if (gbaBackground->screenshotId != (stateId | SCREENSHOT_INVALID)) { struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false); - color_t* pixels = gbaBackground->image; - if (!pixels) { - pixels = anonymousMemoryMap(size); - gbaBackground->image = pixels; - gbaBackground->imageSize = size; - } bool success = false; - if (vf && isPNG(vf) && pixels) { + unsigned w, h; + if (vf && isPNG(vf)) { png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES); png_infop info = png_create_info_struct(png); png_infop end = png_create_info_struct(png); - if (png && info && end) { - success = PNGReadHeader(png, info); - success = success && PNGReadPixels(png, info, pixels, w, h, w); - success = success && PNGReadFooter(png, end); + success = png && info && end; + success = success && PNGReadHeader(png, info); + w = png_get_image_width(png, info); + h = png_get_image_height(png, info); + size_t size = w * h * BYTES_PER_PIXEL; + success = success && (w < 0x4000) && (h < 0x4000); + if (success) { + if (size != gbaBackground->imageSize) { + mappedMemoryFree(pixels, gbaBackground->imageSize); + pixels = anonymousMemoryMap(size); + gbaBackground->image = pixels; + gbaBackground->imageSize = size; + } + success = pixels; } + success = success && PNGReadPixels(png, info, pixels, w, h, w); + if (success) { + gbaBackground->w = w; + gbaBackground->h = h; + } + success = success && PNGReadFooter(png, end); PNGReadClose(png, info, end); } if (vf) { @@ -451,6 +456,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mLOG(GUI_RUNNER, DEBUG, "Loading save..."); mCoreAutoloadSave(runner->core); mCoreAutoloadCheats(runner->core); + mCoreAutoloadPatch(runner->core); if (runner->setup) { mLOG(GUI_RUNNER, DEBUG, "Setting up runner..."); runner->setup(runner); @@ -494,6 +500,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { } mLOG(GUI_RUNNER, INFO, "Game starting"); runner->fps = 0; + bool fastForward = false; while (running) { CircleBufferClear(&runner->fpsBuffer); runner->totalDelta = 0; @@ -502,7 +509,6 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { runner->lastFpsCheck = 1000000LL * tv.tv_sec + tv.tv_usec; int frame = 0; - bool fastForward = false; while (running) { if (runner->running) { running = runner->running(runner); @@ -650,6 +656,9 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { runner->core->reset(runner->core); break; case RUNNER_SAVE_STATE: + // If we are saving state, then the screenshot stored for the state previously should no longer be considered up-to-date. + // Therefore, mark it as stale so that at draw time we load the new save state's screenshot. + ((struct mGUIBackground*) stateSaveMenu.background)->screenshotId |= SCREENSHOT_INVALID; mCoreSaveState(runner->core, item->data.v.u >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA); break; case RUNNER_LOAD_STATE: @@ -835,5 +844,6 @@ THREAD_ENTRY mGUIAutosaveThread(void* context) { } } MutexUnlock(&autosave->mutex); + THREAD_EXIT(0); } #endif diff --git a/src/feature/gui/gui-runner.h b/src/feature/gui/gui-runner.h index fc8e85227..0dc412838 100644 --- a/src/feature/gui/gui-runner.h +++ b/src/feature/gui/gui-runner.h @@ -33,6 +33,8 @@ struct mGUIBackground { color_t* image; size_t imageSize; + uint16_t w; + uint16_t h; unsigned screenshotId; }; diff --git a/src/feature/proxy-backend.c b/src/feature/proxy-backend.c new file mode 100644 index 000000000..fb6e555ed --- /dev/null +++ b/src/feature/proxy-backend.c @@ -0,0 +1,284 @@ +/* Copyright (c) 2013-2023 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 + +static void _mVideoProxyBackendInit(struct VideoBackend* v, WHandle handle) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_INIT, + .handle = handle + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendDeinit(struct VideoBackend* v) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_DEINIT, + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendSetLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct mRectangle* dims) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_SET_LAYER_DIMENSIONS, + .layer = layer, + .data = { + .dims = *dims + } + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendLayerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct mRectangle* dims) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_LAYER_DIMENSIONS, + .layer = layer, + }; + union mVideoBackendCommandData out; + mVideoProxyBackendSubmit(proxy, &cmd, &out); + memcpy(dims, &out.dims, sizeof(*dims)); +} + +static void _mVideoProxyBackendSwap(struct VideoBackend* v) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_SWAP, + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendClear(struct VideoBackend* v) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_CLEAR, + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendContextResized(struct VideoBackend* v, unsigned w, unsigned h) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_CONTEXT_RESIZED, + .data = { + .u = { + .width = w, + .height = h, + } + } + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendSetImageSize(struct VideoBackend* v, enum VideoLayer layer, int w, int h) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_SET_IMAGE_SIZE, + .layer = layer, + .data = { + .s = { + .width = w, + .height = h, + } + } + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendImageSize(struct VideoBackend* v, enum VideoLayer layer, int* w, int* h) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_IMAGE_SIZE, + .layer = layer, + }; + union mVideoBackendCommandData out; + mVideoProxyBackendSubmit(proxy, &cmd, &out); + *w = out.s.width; + *h = out.s.height; +} + +static void _mVideoProxyBackendSetImage(struct VideoBackend* v, enum VideoLayer layer, const void* frame) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_SET_IMAGE, + .layer = layer, + .data = { + .image = frame + } + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static void _mVideoProxyBackendDrawFrame(struct VideoBackend* v) { + struct mVideoProxyBackend* proxy = (struct mVideoProxyBackend*) v; + struct mVideoBackendCommand cmd = { + .cmd = mVB_CMD_DRAW_FRAME, + }; + mVideoProxyBackendSubmit(proxy, &cmd, NULL); +} + +static bool mVideoProxyBackendReadIn(struct mVideoProxyBackend* proxy, struct mVideoBackendCommand* cmd, bool block); +static void mVideoProxyBackendWriteOut(struct mVideoProxyBackend* proxy, const union mVideoBackendCommandData* out); + +void mVideoProxyBackendInit(struct mVideoProxyBackend* proxy, struct VideoBackend* backend) { + proxy->d.init = _mVideoProxyBackendInit; + proxy->d.deinit = _mVideoProxyBackendDeinit; + proxy->d.setLayerDimensions = _mVideoProxyBackendSetLayerDimensions; + proxy->d.layerDimensions = _mVideoProxyBackendLayerDimensions; + proxy->d.swap = _mVideoProxyBackendSwap; + proxy->d.clear = _mVideoProxyBackendClear; + proxy->d.contextResized = _mVideoProxyBackendContextResized; + proxy->d.setImageSize = _mVideoProxyBackendSetImageSize; + proxy->d.imageSize = _mVideoProxyBackendImageSize; + proxy->d.setImage = _mVideoProxyBackendSetImage; + proxy->d.drawFrame = _mVideoProxyBackendDrawFrame; + proxy->backend = backend; + + RingFIFOInit(&proxy->in, 0x400); + RingFIFOInit(&proxy->out, 0x400); + MutexInit(&proxy->inLock); + MutexInit(&proxy->outLock); + ConditionInit(&proxy->inWait); + ConditionInit(&proxy->outWait); + + proxy->wakeupCb = NULL; + proxy->context = NULL; +} + +void mVideoProxyBackendDeinit(struct mVideoProxyBackend* proxy) { + ConditionDeinit(&proxy->inWait); + ConditionDeinit(&proxy->outWait); + MutexDeinit(&proxy->inLock); + MutexDeinit(&proxy->outLock); + RingFIFODeinit(&proxy->in); + RingFIFODeinit(&proxy->out); +} + +void mVideoProxyBackendSubmit(struct mVideoProxyBackend* proxy, const struct mVideoBackendCommand* cmd, union mVideoBackendCommandData* out) { + MutexLock(&proxy->inLock); + while (!RingFIFOWrite(&proxy->in, cmd, sizeof(*cmd))) { + mLOG(VIDEO, DEBUG, "Can't write command. Proxy thread asleep?"); + ConditionWait(&proxy->inWait, &proxy->inLock); + } + MutexUnlock(&proxy->inLock); + if (proxy->wakeupCb) { + proxy->wakeupCb(proxy, proxy->context); + } + + if (!mVideoProxyBackendCommandIsBlocking(cmd->cmd)) { + return; + } + + MutexLock(&proxy->outLock); + while (!RingFIFORead(&proxy->out, out, sizeof(*out))) { + ConditionWait(&proxy->outWait, &proxy->outLock); + } + MutexUnlock(&proxy->outLock); +} + +bool mVideoProxyBackendRun(struct mVideoProxyBackend* proxy, bool block) { + bool ok = false; + do { + struct mVideoBackendCommand cmd; + union mVideoBackendCommandData out; + if (mVideoProxyBackendReadIn(proxy, &cmd, block)) { + switch (cmd.cmd) { + case mVB_CMD_DUMMY: + break; + case mVB_CMD_INIT: + proxy->backend->init(proxy->backend, cmd.handle); + break; + case mVB_CMD_DEINIT: + proxy->backend->deinit(proxy->backend); + break; + case mVB_CMD_SET_LAYER_DIMENSIONS: + proxy->backend->setLayerDimensions(proxy->backend, cmd.layer, &cmd.data.dims); + break; + case mVB_CMD_LAYER_DIMENSIONS: + proxy->backend->layerDimensions(proxy->backend, cmd.layer, &out.dims); + break; + case mVB_CMD_SWAP: + proxy->backend->swap(proxy->backend); + break; + case mVB_CMD_CLEAR: + proxy->backend->clear(proxy->backend); + break; + case mVB_CMD_CONTEXT_RESIZED: + proxy->backend->contextResized(proxy->backend, cmd.data.u.width, cmd.data.u.height); + break; + case mVB_CMD_SET_IMAGE_SIZE: + proxy->backend->setImageSize(proxy->backend, cmd.layer, cmd.data.s.width, cmd.data.s.height); + break; + case mVB_CMD_IMAGE_SIZE: + proxy->backend->imageSize(proxy->backend, cmd.layer, &out.s.width, &out.s.height); + break; + case mVB_CMD_SET_IMAGE: + proxy->backend->setImage(proxy->backend, cmd.layer, cmd.data.image); + break; + case mVB_CMD_DRAW_FRAME: + proxy->backend->drawFrame(proxy->backend); + break; + } + if (mVideoProxyBackendCommandIsBlocking(cmd.cmd)) { + mVideoProxyBackendWriteOut(proxy, &out); + } + ok = true; + } + } while (block); + return ok; +} + +bool mVideoProxyBackendReadIn(struct mVideoProxyBackend* proxy, struct mVideoBackendCommand* cmd, bool block) { + bool gotCmd = false; + MutexLock(&proxy->inLock); + do { + gotCmd = RingFIFORead(&proxy->in, cmd, sizeof(*cmd)); + ConditionWake(&proxy->inWait); + // TODO: interlock? + if (block && !gotCmd) { + mLOG(VIDEO, DEBUG, "Can't read command. Runner thread asleep?"); + } + } while (block && !gotCmd); + MutexUnlock(&proxy->inLock); + return gotCmd; +} + +void mVideoProxyBackendWriteOut(struct mVideoProxyBackend* proxy, const union mVideoBackendCommandData* out) { + bool gotReply = false; + MutexLock(&proxy->outLock); + while (!gotReply) { + gotReply = RingFIFOWrite(&proxy->out, out, sizeof(*out)); + ConditionWake(&proxy->outWait); + // TOOD: interlock? + if (!gotReply) { + mLOG(VIDEO, DEBUG, "Can't write reply. Runner thread asleep?"); + } + } + MutexUnlock(&proxy->outLock); +} + +bool mVideoProxyBackendCommandIsBlocking(enum mVideoBackendCommandType cmd) { + switch (cmd) { + case mVB_CMD_DUMMY: + case mVB_CMD_CONTEXT_RESIZED: + case mVB_CMD_SET_LAYER_DIMENSIONS: + case mVB_CMD_CLEAR: + case mVB_CMD_SET_IMAGE_SIZE: + case mVB_CMD_DRAW_FRAME: + return false; + case mVB_CMD_INIT: + case mVB_CMD_DEINIT: + case mVB_CMD_LAYER_DIMENSIONS: + case mVB_CMD_SWAP: + case mVB_CMD_IMAGE_SIZE: + case mVB_CMD_SET_IMAGE: + return true; + } + + return true; +} diff --git a/src/feature/sqlite3/no-intro.c b/src/feature/sqlite3/no-intro.c index d54e188ff..649364de6 100644 --- a/src/feature/sqlite3/no-intro.c +++ b/src/feature/sqlite3/no-intro.c @@ -17,7 +17,7 @@ struct NoIntroDB { }; struct NoIntroDB* NoIntroDBLoad(const char* path) { - struct NoIntroDB* db = malloc(sizeof(*db)); + struct NoIntroDB* db = calloc(1, sizeof(*db)); if (sqlite3_open_v2(path, &db->db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL)) { goto error; @@ -60,9 +60,6 @@ struct NoIntroDB* NoIntroDBLoad(const char* path) { return db; error: - if (db->crc32) { - sqlite3_finalize(db->crc32); - } NoIntroDBDestroy(db); return NULL; @@ -285,8 +282,12 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) { } void NoIntroDBDestroy(struct NoIntroDB* db) { - sqlite3_finalize(db->crc32); - sqlite3_close(db->db); + if (db->crc32) { + sqlite3_finalize(db->crc32); + } + if (db->db) { + sqlite3_close(db->db); + } free(db); } diff --git a/src/feature/thread-proxy.c b/src/feature/thread-proxy.c index d2956ed95..c3878e896 100644 --- a/src/feature/thread-proxy.c +++ b/src/feature/thread-proxy.c @@ -207,7 +207,7 @@ static THREAD_ENTRY _proxyThread(void* logger) { } } MutexUnlock(&proxyRenderer->mutex); - return 0; + THREAD_EXIT(0); } #endif diff --git a/src/feature/updater.c b/src/feature/updater.c index e9f47f440..e50ed0fa2 100644 --- a/src/feature/updater.c +++ b/src/feature/updater.c @@ -148,7 +148,7 @@ bool mUpdateLoad(const struct mCoreConfig* config, const char* prefix, struct mU snprintf(key, sizeof(key), "%s.path", prefix); update->path = mCoreConfigGetValue(config, key); snprintf(key, sizeof(key), "%s.size", prefix); - uint32_t size = 0; + unsigned size = 0; mCoreConfigGetUIntValue(config, key, &size); if (!update->path && !size) { return false; diff --git a/src/feature/video-backend.c b/src/feature/video-backend.c new file mode 100644 index 000000000..ba13bbe7d --- /dev/null +++ b/src/feature/video-backend.c @@ -0,0 +1,45 @@ +/* Copyright (c) 2013-2023 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 + +mLOG_DEFINE_CATEGORY(VIDEO, "Video backend", "video"); + +void VideoBackendGetFrame(const struct VideoBackend* v, struct mRectangle* frame) { + memset(frame, 0, sizeof(*frame)); + int i; + for (i = 0; i < VIDEO_LAYER_MAX; ++i) { + struct mRectangle dims; + v->layerDimensions(v, i, &dims); + mRectangleUnion(frame, &dims); + } +} + +void VideoBackendGetFrameSize(const struct VideoBackend* v, unsigned* width, unsigned* height) { + struct mRectangle frame; + VideoBackendGetFrame(v, &frame); + *width = frame.width; + *height = frame.height; +} + +void VideoBackendRecenter(struct VideoBackend* v, unsigned scale) { + static const int centeredLayers[] = {VIDEO_LAYER_BACKGROUND, -1}; + struct mRectangle frame = {0}; + v->imageSize(v, VIDEO_LAYER_IMAGE, &frame.width, &frame.height); + if (scale == 0) { + scale = 1; + } + + size_t i; + for (i = 0; centeredLayers[i] >= 0; ++i) { + int width, height; + struct mRectangle dims = {0}; + v->imageSize(v, centeredLayers[i], &width, &height); + dims.width = width * scale; + dims.height = height * scale; + mRectangleCenter(&frame, &dims); + v->setLayerDimensions(v, centeredLayers[i], &dims); + } +} diff --git a/src/feature/video-logger.c b/src/feature/video-logger.c index ae2fa046e..fb2065b42 100644 --- a/src/feature/video-logger.c +++ b/src/feature/video-logger.c @@ -382,10 +382,7 @@ static void _copyVf(struct VFile* dest, struct VFile* src) { static void _compress(struct VFile* dest, struct VFile* src) { uint8_t writeBuffer[0x800]; uint8_t compressBuffer[0x400]; - z_stream zstr; - zstr.zalloc = Z_NULL; - zstr.zfree = Z_NULL; - zstr.opaque = Z_NULL; + z_stream zstr = {0}; zstr.avail_in = 0; zstr.avail_out = sizeof(compressBuffer); zstr.next_out = (Bytef*) compressBuffer; @@ -425,10 +422,7 @@ static void _compress(struct VFile* dest, struct VFile* src) { static bool _decompress(struct VFile* dest, struct VFile* src, size_t compressedLength) { uint8_t fbuffer[0x400]; uint8_t zbuffer[0x800]; - z_stream zstr; - zstr.zalloc = Z_NULL; - zstr.zfree = Z_NULL; - zstr.opaque = Z_NULL; + z_stream zstr = {0}; zstr.avail_in = 0; zstr.avail_out = sizeof(zbuffer); zstr.next_out = (Bytef*) zbuffer; diff --git a/src/gb/audio.c b/src/gb/audio.c index d2d6a9260..996fce66d 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -100,22 +100,24 @@ void GBAudioReset(struct GBAudio* audio) { audio->ch3 = (struct GBAudioWaveChannel) { .bank = 0 }; audio->ch4 = (struct GBAudioNoiseChannel) { .nSamples = 0 }; // TODO: DMG randomness - audio->ch3.wavedata8[0] = 0x00; - audio->ch3.wavedata8[1] = 0xFF; - audio->ch3.wavedata8[2] = 0x00; - audio->ch3.wavedata8[3] = 0xFF; - audio->ch3.wavedata8[4] = 0x00; - audio->ch3.wavedata8[5] = 0xFF; - audio->ch3.wavedata8[6] = 0x00; - audio->ch3.wavedata8[7] = 0xFF; - audio->ch3.wavedata8[8] = 0x00; - audio->ch3.wavedata8[9] = 0xFF; - audio->ch3.wavedata8[10] = 0x00; - audio->ch3.wavedata8[11] = 0xFF; - audio->ch3.wavedata8[12] = 0x00; - audio->ch3.wavedata8[13] = 0xFF; - audio->ch3.wavedata8[14] = 0x00; - audio->ch3.wavedata8[15] = 0xFF; + if (audio->style != GB_AUDIO_GBA) { + audio->ch3.wavedata8[0] = 0x00; + audio->ch3.wavedata8[1] = 0xFF; + audio->ch3.wavedata8[2] = 0x00; + audio->ch3.wavedata8[3] = 0xFF; + audio->ch3.wavedata8[4] = 0x00; + audio->ch3.wavedata8[5] = 0xFF; + audio->ch3.wavedata8[6] = 0x00; + audio->ch3.wavedata8[7] = 0xFF; + audio->ch3.wavedata8[8] = 0x00; + audio->ch3.wavedata8[9] = 0xFF; + audio->ch3.wavedata8[10] = 0x00; + audio->ch3.wavedata8[11] = 0xFF; + audio->ch3.wavedata8[12] = 0x00; + audio->ch3.wavedata8[13] = 0xFF; + audio->ch3.wavedata8[14] = 0x00; + audio->ch3.wavedata8[15] = 0xFF; + } audio->ch4 = (struct GBAudioNoiseChannel) { .envelope = { .dead = 2 } }; audio->frame = 0; audio->sampleInterval = SAMPLE_INTERVAL * GB_MAX_SAMPLES; @@ -138,6 +140,9 @@ void GBAudioReset(struct GBAudio* audio) { } void GBAudioResizeBuffer(struct GBAudio* audio, size_t samples) { + if (samples > BLIP_BUFFER_SIZE / 2) { + samples = BLIP_BUFFER_SIZE / 2; + } mCoreSyncLockAudio(audio->p->sync); audio->samples = samples; blip_clear(audio->left); @@ -380,11 +385,7 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { if (GBAudioRegisterNoiseControlIsRestart(value)) { audio->playingCh4 = _resetEnvelope(&audio->ch4.envelope); - if (audio->ch4.power) { - audio->ch4.lfsr = 0x7F; - } else { - audio->ch4.lfsr = 0x7FFF; - } + audio->ch4.lfsr = 0; if (!audio->ch4.length) { audio->ch4.length = 64; if (audio->ch4.stop && !(audio->frame & 1)) { @@ -503,7 +504,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { GBAudioSample(audio, timestamp); } - if (audio->playingCh1 && (channels & 0x1) && audio->ch1.envelope.dead != 2) { + if ((channels & 0x1) && ((audio->playingCh1 && audio->ch1.envelope.dead != 2) || timestamp - audio->ch1.lastUpdate > 0x40000000 || (channels == 0x1))) { int period = 4 * (2048 - audio->ch1.control.frequency) * audio->timingFactor; int32_t diff = timestamp - audio->ch1.lastUpdate; if (diff >= period) { @@ -513,7 +514,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { _updateSquareSample(&audio->ch1); } } - if (audio->playingCh2 && (channels & 0x2) && audio->ch2.envelope.dead != 2) { + if ((channels & 0x2) && ((audio->playingCh2 && audio->ch2.envelope.dead != 2) || timestamp - audio->ch2.lastUpdate > 0x40000000 || (channels == 0x2))) { int period = 4 * (2048 - audio->ch2.control.frequency) * audio->timingFactor; int32_t diff = timestamp - audio->ch2.lastUpdate; if (diff >= period) { @@ -596,24 +597,58 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { } } if (audio->playingCh4 && (channels & 0x8)) { + const uint16_t noiseMaskTable[0x40] = { + 0x3f, 0x3e, 0x3c, 0x3d, 0x39, 0x38, 0x3a, 0x3b, + 0x33, 0x32, 0x30, 0x31, 0x35, 0x34, 0x36, 0x37, + 0x27, 0x26, 0x24, 0x25, 0x21, 0x20, 0x22, 0x23, + 0x2b, 0x2a, 0x28, 0x29, 0x2d, 0x2c, 0x2e, 0x2f, + 0x0f, 0x0e, 0x0c, 0x0d, 0x09, 0x08, 0x0a, 0x0b, + 0x03, 0x02, 0x00, 0x01, 0x05, 0x04, 0x06, 0x07, + 0x17, 0x16, 0x14, 0x15, 0x11, 0x10, 0x12, 0x13, + 0x1b, 0x1a, 0x18, 0x19, 0x1d, 0x1c, 0x1e, 0x1f + }; + const uint16_t noisePopulationTable[0x40] = { + 6, 5, 4, 5, 4, 3, 4, 5, 4, 3, 2, 3, 4, 3, 4, 5, + 4, 3, 2, 3, 2, 1, 2, 3, 4, 3, 2, 3, 4, 3, 4, 5, + 4, 3, 2, 3, 2, 1, 2, 3, 2, 1, 0, 1, 2, 1, 2, 3, + 4, 3, 2, 3, 2, 1, 2, 3, 4, 3, 2, 3, 4, 3, 4, 5 + }; int32_t cycles = audio->ch4.ratio ? 2 * audio->ch4.ratio : 1; cycles <<= audio->ch4.frequency; cycles *= 8 * audio->timingFactor; int32_t diff = timestamp - audio->ch4.lastEvent; if (diff >= cycles) { - int32_t last; + int32_t last = 0; int samples = 0; int positiveSamples = 0; int lsb; - int coeff = 0x60; - if (!audio->ch4.power) { - coeff <<= 8; + int coeff; + if (audio->ch4.power) { + // TODO: Can this be batched too? + coeff = 0x4040; + } else { + int bits = 0; + // Batch 5 steps at a time when possible + for (; last + cycles * 5 <= diff; last += cycles * 5) { + bits = audio->ch4.lfsr & 0x3F; + audio->ch4.lfsr >>= 5; + audio->ch4.lfsr |= 0x4000 * noiseMaskTable[bits] >> 4; + audio->ch4.lfsr &= 0x7FFF; + samples += 5; + positiveSamples += noisePopulationTable[bits]; + } + lsb = noiseMaskTable[bits] & 1; + coeff = 0x4000; } - for (last = 0; last + cycles <= diff; last += cycles) { - lsb = audio->ch4.lfsr & 1; + for (; last + cycles <= diff; last += cycles) { + lsb = (audio->ch4.lfsr ^ (audio->ch4.lfsr >> 1) ^ 1) & 1; audio->ch4.lfsr >>= 1; - audio->ch4.lfsr ^= lsb * coeff; + if (lsb) { + audio->ch4.lfsr |= coeff; + } else { + audio->ch4.lfsr &= ~coeff; + } ++samples; positiveSamples += lsb; } @@ -644,7 +679,9 @@ void GBAudioUpdateFrame(struct GBAudio* audio) { if (audio->ch1.sweep.enable) { --audio->ch1.sweep.step; if (audio->ch1.sweep.step == 0) { - audio->playingCh1 = _updateSweep(&audio->ch1, false); + if (!_updateSweep(&audio->ch1, false)) { + audio->playingCh1 = false; + } *audio->nr52 &= ~0x0001; *audio->nr52 |= audio->playingCh1; } @@ -843,9 +880,6 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { bool _resetEnvelope(struct GBAudioEnvelope* envelope) { envelope->currentVolume = envelope->initialVolume; _updateEnvelopeDead(envelope); - if (!envelope->dead) { - envelope->nextStep = envelope->stepTime; - } return envelope->initialVolume || envelope->direction; } @@ -877,12 +911,25 @@ void _writeDuty(struct GBAudioEnvelope* envelope, uint8_t value) { } bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudioStyle style) { + bool oldDirection = envelope->direction; envelope->stepTime = GBAudioRegisterSweepGetStepTime(value); envelope->direction = GBAudioRegisterSweepGetDirection(value); envelope->initialVolume = GBAudioRegisterSweepGetInitialVolume(value); - if (style == GB_AUDIO_DMG && !envelope->stepTime) { + if (!envelope->stepTime) { // TODO: Improve "zombie" mode - ++envelope->currentVolume; + if (style == GB_AUDIO_DMG) { + ++envelope->currentVolume; + } else if (style == GB_AUDIO_CGB) { + if (envelope->direction == oldDirection) { + if (envelope->direction) { + ++envelope->currentVolume; + } else { + envelope->currentVolume += 2; + } + } else { + envelope->currentVolume = 0; + } + } envelope->currentVolume &= 0xF; } _updateEnvelopeDead(envelope); @@ -930,6 +977,7 @@ static void _updateEnvelopeDead(struct GBAudioEnvelope* envelope) { envelope->dead = 1; } else { envelope->dead = 0; + envelope->nextStep = envelope->stepTime; } } @@ -1089,6 +1137,8 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch4.lastEvent = currentTime + (when & (cycles - 1)) - cycles; } } + audio->ch4.nSamples = 0; + audio->ch4.samples = 0; } void GBAudioSerialize(const struct GBAudio* audio, struct GBSerializedState* state) { diff --git a/src/gb/core.c b/src/gb/core.c index 7edb1a607..9154221d6 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -8,9 +8,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -60,6 +60,15 @@ static const struct mCoreMemoryBlock _GBCMemoryBlocks[] = { { GB_BASE_HRAM, "hram", "HRAM", "High RAM", GB_BASE_HRAM, GB_BASE_HRAM + GB_SIZE_HRAM, GB_SIZE_HRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, }; +static const struct mCoreScreenRegion _GBScreenRegions[] = { + { 0, "Screen", 0, 0, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS } +}; + +static const struct mCoreScreenRegion _SGBScreenRegions[] = { + { 0, "Screen", (SGB_VIDEO_HORIZONTAL_PIXELS - GB_VIDEO_HORIZONTAL_PIXELS) / 2, (SGB_VIDEO_VERTICAL_PIXELS - GB_VIDEO_VERTICAL_PIXELS) / 2, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS }, + { 1, "Border", 0, 0, SGB_VIDEO_HORIZONTAL_PIXELS, SGB_VIDEO_VERTICAL_PIXELS }, +}; + static const struct mCoreRegisterInfo _GBRegisters[] = { { "b", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, { "c", NULL, 1, 0xFF, mCORE_REGISTER_GPR }, @@ -90,6 +99,8 @@ struct GBCore { uint8_t keys; struct mCPUComponent* components[CPU_COMPONENT_MAX]; const struct Configuration* overrides; + struct GBCartridgeOverride override; + bool hasOverride; struct mDebuggerPlatform* debuggerPlatform; struct mCheatDevice* cheatDevice; struct mCoreMemoryBlock memoryBlocks[8]; @@ -115,6 +126,8 @@ static bool _GBCoreInit(struct mCore* core) { gbcore->logContext = NULL; #endif memcpy(gbcore->memoryBlocks, _GBMemoryBlocks, sizeof(_GBMemoryBlocks)); + memset(&gbcore->override, 0, sizeof(gbcore->override)); + gbcore->hasOverride = false; GBCreate(gb); memset(gbcore->components, 0, sizeof(gbcore->components)); @@ -355,14 +368,42 @@ static void _GBCoreReloadConfigOption(struct mCore* core, const char* option, co } } -static void _GBCoreDesiredVideoDimensions(const struct mCore* core, unsigned* width, unsigned* height) { +static void _GBCoreSetOverride(struct mCore* core, const void* override) { + struct GBCore* gbcore = (struct GBCore*) core; + memcpy(&gbcore->override, override, sizeof(gbcore->override)); + gbcore->hasOverride = true; +} + +static void _GBCoreBaseVideoSize(const struct mCore* core, unsigned* width, unsigned* height) { + UNUSED(core); + *width = SGB_VIDEO_HORIZONTAL_PIXELS; + *height = SGB_VIDEO_VERTICAL_PIXELS; +} + +static void _GBCoreCurrentVideoSize(const struct mCore* core, unsigned* width, unsigned* height) { const struct GB* gb = core->board; if (gb && (!(gb->model & GB_MODEL_SGB) || !gb->video.sgbBorders)) { *width = GB_VIDEO_HORIZONTAL_PIXELS; *height = GB_VIDEO_VERTICAL_PIXELS; } else { - *width = 256; - *height = 224; + *width = SGB_VIDEO_HORIZONTAL_PIXELS; + *height = SGB_VIDEO_VERTICAL_PIXELS; + } +} + +static unsigned _GBCoreVideoScale(const struct mCore* core) { + UNUSED(core); + return 1; +} + +static size_t _GBCoreScreenRegions(const struct mCore* core, const struct mCoreScreenRegion** regions) { + const struct GB* gb = core->board; + if (gb && (!(gb->model & GB_MODEL_SGB) || !gb->video.sgbBorders)) { + *regions = _GBScreenRegions; + return 1; + } else { + *regions = _SGBScreenRegions; + return 2; } } @@ -424,7 +465,7 @@ static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { gb->stream = stream; if (stream && stream->videoDimensionsChanged) { unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); stream->videoDimensionsChanged(stream, width, height); } if (stream && stream->audioRateChanged) { @@ -510,14 +551,15 @@ static void _GBCoreReset(struct mCore* core) { mCoreConfigGetIntValue(&core->config, "useCgbColors", &doColorOverride); } - struct GBCartridgeOverride override; const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; - override.headerCrc32 = doCrc32(cart, sizeof(*cart)); - bool modelOverride = GBOverrideFind(gbcore->overrides, &override) || (doColorOverride && GBOverrideColorFind(&override, doColorOverride)); - if (modelOverride) { - GBOverrideApply(gb, &override); + if (!gbcore->hasOverride) { + gbcore->override.headerCrc32 = doCrc32(cart, sizeof(*cart)); + gbcore->hasOverride = GBOverrideFind(gbcore->overrides, &gbcore->override) || (doColorOverride && GBOverrideColorFind(&gbcore->override, doColorOverride)); } - if (!modelOverride || override.model == GB_MODEL_AUTODETECT) { + if (gbcore->hasOverride) { + GBOverrideApply(gb, &gbcore->override); + } + if (!gbcore->hasOverride || gbcore->override.model == GB_MODEL_AUTODETECT) { const char* modelGB = mCoreConfigGetValue(&core->config, "gb.model"); const char* modelSGB = mCoreConfigGetValue(&core->config, "sgb.model"); const char* modelCGB = mCoreConfigGetValue(&core->config, "cgb.model"); @@ -607,16 +649,16 @@ static void _GBCoreReset(struct mCore* core) { switch (gb->model) { case GB_MODEL_DMG: case GB_MODEL_MGB: // TODO - strncat(path, PATH_SEP "gb_bios.bin", PATH_MAX - strlen(path)); + strncat(path, PATH_SEP "gb_bios.bin", PATH_MAX - strlen(path) - 1); break; case GB_MODEL_SGB: case GB_MODEL_SGB2: // TODO - strncat(path, PATH_SEP "sgb_bios.bin", PATH_MAX - strlen(path)); + strncat(path, PATH_SEP "sgb_bios.bin", PATH_MAX - strlen(path) - 1); break; case GB_MODEL_CGB: case GB_MODEL_AGB: case GB_MODEL_SCGB: - strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path)); + strncat(path, PATH_SEP "gbc_bios.bin", PATH_MAX - strlen(path) - 1); break; default: break; @@ -644,8 +686,10 @@ static void _GBCoreReset(struct mCore* core) { size_t i; for (i = 0; i < sizeof(gbcore->memoryBlocks) / sizeof(*gbcore->memoryBlocks); ++i) { if (gbcore->memoryBlocks[i].id == GB_REGION_CART_BANK0) { + gbcore->memoryBlocks[i].size = gb->memory.romSize; gbcore->memoryBlocks[i].maxSegment = gb->memory.romSize / GB_SIZE_CART_BANK0; } else if (gbcore->memoryBlocks[i].id == GB_REGION_EXTERNAL_RAM) { + gbcore->memoryBlocks[i].size = gb->sramSize; gbcore->memoryBlocks[i].maxSegment = gb->sramSize / GB_SIZE_EXTERNAL_RAM; } else { continue; @@ -764,6 +808,20 @@ static void _GBCoreSetPeripheral(struct mCore* core, int type, void* periph) { } } +static void* _GBCoreGetPeripheral(struct mCore* core, int type) { + struct GB* gb = core->board; + switch (type) { + case mPERIPH_ROTATION: + return gb->memory.rotation; + case mPERIPH_RUMBLE: + return gb->memory.rumble; + case mPERIPH_IMAGE_SOURCE: + return gb->memory.cam; + default: + return NULL; + } +} + static uint32_t _GBCoreBusRead8(struct mCore* core, uint32_t address) { struct SM83Core* cpu = core->cpu; return cpu->memory.load8(cpu, address); @@ -1030,6 +1088,9 @@ static struct CLIDebuggerSystem* _GBCoreCliDebuggerSystem(struct mCore* core) { static void _GBCoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) { struct SM83Core* cpu = core->cpu; + if (core->debugger == debugger) { + return; + } if (core->debugger) { SM83HotplugDetach(cpu, CPU_COMPONENT_DEBUGGER); } @@ -1050,7 +1111,7 @@ static void _GBCoreDetachDebugger(struct mCore* core) { static void _GBCoreLoadSymbols(struct mCore* core, struct VFile* vf) { core->symbolTable = mDebuggerSymbolTableCreate(); #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 - if (!vf) { + if (!vf && core->dirs.base) { vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".sym", O_RDONLY); } #endif @@ -1232,7 +1293,11 @@ struct mCore* GBCoreCreate(void) { core->setSync = _GBCoreSetSync; core->loadConfig = _GBCoreLoadConfig; core->reloadConfigOption = _GBCoreReloadConfigOption; - core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions; + core->setOverride = _GBCoreSetOverride; + core->baseVideoSize = _GBCoreBaseVideoSize; + core->currentVideoSize = _GBCoreCurrentVideoSize; + core->videoScale = _GBCoreVideoScale; + core->screenRegions = _GBCoreScreenRegions; core->setVideoBuffer = _GBCoreSetVideoBuffer; core->setVideoGLTex = _GBCoreSetVideoGLTex; core->getPixels = _GBCoreGetPixels; @@ -1269,6 +1334,7 @@ struct mCore* GBCoreCreate(void) { core->getGameTitle = _GBCoreGetGameTitle; core->getGameCode = _GBCoreGetGameCode; core->setPeripheral = _GBCoreSetPeripheral; + core->getPeripheral = _GBCoreGetPeripheral; core->busRead8 = _GBCoreBusRead8; core->busRead16 = _GBCoreBusRead16; core->busRead32 = _GBCoreBusRead32; diff --git a/src/gb/debugger/cli.c b/src/gb/debugger/cli.c index d4089d40f..f32f299a3 100644 --- a/src/gb/debugger/cli.c +++ b/src/gb/debugger/cli.c @@ -3,7 +3,7 @@ * 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 +#include #include #include @@ -58,7 +58,7 @@ static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { if (gbDebugger->frameAdvance) { if (!gbDebugger->inVblank && GBRegisterSTATGetMode(((struct GB*) gbDebugger->core->board)->memory.io[GB_REG_STAT]) == 1) { - mDebuggerEnter(&gbDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0); + mDebuggerEnter(gbDebugger->d.p->d.p, DEBUGGER_ENTER_MANUAL, 0); gbDebugger->frameAdvance = false; return false; } @@ -70,7 +70,8 @@ static bool _GBCLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - debugger->d.state = DEBUGGER_CALLBACK; + debugger->d.needsCallback = true; + mDebuggerUpdatePaused(debugger->d.p); struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system; gbDebugger->frameAdvance = true; diff --git a/src/gb/debugger/debugger.c b/src/gb/debugger/debugger.c index e1dda7a8d..cc05bb7a5 100644 --- a/src/gb/debugger/debugger.c +++ b/src/gb/debugger/debugger.c @@ -28,7 +28,7 @@ static const struct SM83Segment _GBCSegments[] = { static void _printStatus(struct CLIDebuggerSystem* debugger) { struct CLIDebuggerBackend* be = debugger->p->backend; - struct GB* gb = debugger->p->d.core->board; + struct GB* gb = debugger->p->d.p->core->board; be->printf(be, "IE: %02X IF: %02X IME: %i\n", gb->memory.ie, gb->memory.io[GB_REG_IF], gb->memory.ime); be->printf(be, "LCDC: %02X STAT: %02X LY: %02X\n", gb->memory.io[GB_REG_LCDC], gb->memory.io[GB_REG_STAT] | 0x80, gb->memory.io[GB_REG_LY]); be->printf(be, "Next video mode: %i\n", mTimingUntil(&gb->timing, &gb->video.modeEvent) / 4); diff --git a/src/gb/gb.c b/src/gb/gb.c index a3a870f28..958312524 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -260,9 +260,13 @@ void GBResizeSram(struct GB* gb, size_t size) { } struct VFile* vf = gb->sramVf; if (vf) { + // We have a vf + ssize_t vfSize = vf->size(vf); if (vf == gb->sramRealVf) { - ssize_t vfSize = vf->size(vf); + // This is the real save file, not a masked one if (vfSize >= 0 && (size_t) vfSize < size) { + // We need to grow the file + // Make sure to copy the footer data, if any uint8_t extdataBuffer[0x100]; if (vfSize & 0xFF) { vf->seek(vf, -(vfSize & 0xFF), SEEK_END); @@ -270,6 +274,7 @@ void GBResizeSram(struct GB* gb, size_t size) { } if (gb->memory.sram) { vf->unmap(vf, gb->memory.sram, gb->sramSize); + gb->memory.sram = NULL; } vf->truncate(vf, size + (vfSize & 0xFF)); if (vfSize & 0xFF) { @@ -281,24 +286,36 @@ void GBResizeSram(struct GB* gb, size_t size) { memset(&gb->memory.sram[vfSize], 0xFF, size - vfSize); } } else if (size > gb->sramSize || !gb->memory.sram) { + // We aren't growing the file, but we are changing our mapping of it if (gb->memory.sram) { vf->unmap(vf, gb->memory.sram, gb->sramSize); + gb->memory.sram = NULL; } if (size) { gb->memory.sram = vf->map(vf, size, MAP_WRITE); } } } else { + // This is a masked save file if (gb->memory.sram) { vf->unmap(vf, gb->memory.sram, gb->sramSize); } - if (vf->size(vf) < gb->sramSize) { - void* sram = vf->map(vf, vf->size(vf), MAP_READ); - struct VFile* newVf = VFileMemChunk(sram, vf->size(vf)); - vf->unmap(vf, sram,vf->size(vf)); - vf = newVf; - gb->sramVf = newVf; - vf->truncate(vf, size); + if ((vfSize <= 0 && size) || (size_t) vfSize < size) { + // The loaded mask file is too small. Since these can be read-only, + // we need to make a new one of the right size + if (vfSize < 0) { + vfSize = 0; + } + gb->sramVf = VFileMemChunk(NULL, size); + uint8_t* sram = gb->sramVf->map(gb->sramVf, size, MAP_WRITE); + if (vfSize > 0) { + vf->seek(vf, 0, SEEK_SET); + vf->read(vf, sram, vfSize); + } + memset(&sram[vfSize], 0xFF, size - vfSize); + gb->sramVf->unmap(gb->sramVf, sram, size); + vf->close(vf); + vf = gb->sramVf; } if (size) { gb->memory.sram = vf->map(vf, size, MAP_READ); @@ -308,6 +325,8 @@ void GBResizeSram(struct GB* gb, size_t size) { gb->memory.sram = NULL; } } else if (size) { + // There's no vf, so let's make it only memory-backed + // TODO: Investigate just using a VFileMemChunk instead of this hybrid approach uint8_t* newSram = anonymousMemoryMap(size); if (gb->memory.sram) { if (size > gb->sramSize) { @@ -405,7 +424,9 @@ void GBUnloadROM(struct GB* gb) { if (gb->romVf) { #ifndef FIXED_ROM_BUFFER - gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); + if (gb->isPristine && gb->memory.rom) { + gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); + } #endif gb->romVf->close(gb->romVf); gb->romVf = NULL; @@ -453,6 +474,9 @@ void GBApplyPatch(struct GB* gb, struct Patch* patch) { if (patchedSize > GB_SIZE_CART_MAX) { patchedSize = GB_SIZE_CART_MAX; } + + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + uint8_t type = cart->type; void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX); if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) { mappedMemoryFree(newRom, GB_SIZE_CART_MAX); @@ -471,6 +495,12 @@ void GBApplyPatch(struct GB* gb, struct Patch* patch) { } gb->memory.rom = newRom; gb->memory.romSize = patchedSize; + + cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + if (cart->type != type) { + gb->memory.mbcType = GB_MBC_AUTODETECT; + GBMBCInit(gb); + } gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); } @@ -528,6 +558,23 @@ bool GBIsBIOS(struct VFile* vf) { } } +bool GBIsCompatibleBIOS(struct VFile* vf, enum GBModel model) { + switch (_GBBiosCRC32(vf)) { + case DMG_BIOS_CHECKSUM: + case DMG0_BIOS_CHECKSUM: + case MGB_BIOS_CHECKSUM: + case SGB_BIOS_CHECKSUM: + case SGB2_BIOS_CHECKSUM: + return model < GB_MODEL_CGB; + case CGB_BIOS_CHECKSUM: + case CGB0_BIOS_CHECKSUM: + case AGB_BIOS_CHECKSUM: + return model >= GB_MODEL_CGB; + default: + return false; + } +} + void GBReset(struct SM83Core* cpu) { struct GB* gb = (struct GB*) cpu->master; gb->memory.romBase = gb->memory.rom; @@ -560,7 +607,7 @@ void GBReset(struct SM83Core* cpu) { GBMemoryReset(gb); if (gb->biosVf) { - if (!GBIsBIOS(gb->biosVf)) { + if (!GBIsCompatibleBIOS(gb->biosVf, gb->model)) { gb->biosVf->close(gb->biosVf); gb->biosVf = NULL; } else { @@ -815,6 +862,7 @@ void GBDetectModel(struct GB* gb) { gb->model = GB_MODEL_SGB2; break; case CGB_BIOS_CHECKSUM: + case CGB0_BIOS_CHECKSUM: gb->model = GB_MODEL_CGB; break; case AGB_BIOS_CHECKSUM: diff --git a/src/gb/io.c b/src/gb/io.c index ba4473550..560ad7e62 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -491,7 +491,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { return; case GB_REG_SVBK: GBMemorySwitchWramBank(&gb->memory, value); - value = gb->memory.wramCurrentBank; + value &= 7; break; default: goto failed; diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 27ccfe784..76c005f96 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -219,7 +219,7 @@ static enum GBMemoryBankControllerType _detectUnlMBC(const uint8_t* mem, size_t if (cart->type == 0x01) { // Make sure we're not using a "fixed" version return GB_UNL_LI_CHENG; } - if ((0x8000 << cart->romSize) != size) { + if ((0x8000U << cart->romSize) != size) { return GB_UNL_LI_CHENG; } break; diff --git a/src/gb/mbc/unlicensed.c b/src/gb/mbc/unlicensed.c index 58725fa98..1577a15fa 100644 --- a/src/gb/mbc/unlicensed.c +++ b/src/gb/mbc/unlicensed.c @@ -227,7 +227,7 @@ void _GBNTOld2(struct GB* gb, uint16_t address, uint8_t value) { mbcState->rumble = !!(value & 0x80); } - if (mbcState->rumble) { + if (mbcState->rumble && memory->rumble) { memory->rumble->setRumble(memory->rumble, !!(mbcState->swapped ? value & 0x08 : value & 0x02)); } break; diff --git a/src/gb/memory.c b/src/gb/memory.c index 5c4d97876..e41050784 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -14,6 +14,7 @@ #include #include +#include mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory", "gb.memory"); @@ -474,13 +475,14 @@ uint8_t GBView8(struct SM83Core* cpu, uint16_t address, int segment) { if (memory->rtcAccess) { return memory->rtcRegs[memory->activeRtcReg]; } else if (memory->sramAccess) { - if (segment < 0 && memory->sram) { - return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; - } else if ((size_t) segment * GB_SIZE_EXTERNAL_RAM < gb->sramSize) { - return memory->sram[(address & (GB_SIZE_EXTERNAL_RAM - 1)) + segment *GB_SIZE_EXTERNAL_RAM]; - } else { - return 0xFF; + if (memory->sram) { + if (segment < 0) { + return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)]; + } else if ((size_t) segment * GB_SIZE_EXTERNAL_RAM < gb->sramSize) { + return memory->sram[(address & (GB_SIZE_EXTERNAL_RAM - 1)) + segment *GB_SIZE_EXTERNAL_RAM]; + } } + return 0xFF; } else if (memory->mbcRead) { return memory->mbcRead(memory, address); } else if (memory->mbcType == GB_HuC3) { @@ -797,6 +799,10 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) { state->huc3Registers[i] |= memory->mbcState.huc3.registers[i * 2 + 1] << 4; } break; + case GB_POCKETCAM: + state->memory.pocketCam.registersActive = memory->mbcState.pocketCam.registersActive; + memcpy(state->pocketCamRegisters, memory->mbcState.pocketCam.registers, sizeof(memory->mbcState.pocketCam.registers)); + break; case GB_MMM01: state->memory.mmm01.locked = memory->mbcState.mmm01.locked; state->memory.mmm01.bank0 = memory->mbcState.mmm01.currentBank0; @@ -948,6 +954,10 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) { memory->mbcState.huc3.registers[i * 2 + 1] = state->huc3Registers[i] >> 4; } break; + case GB_POCKETCAM: + memory->mbcState.pocketCam.registersActive = state->memory.pocketCam.registersActive; + memcpy(memory->mbcState.pocketCam.registers, state->pocketCamRegisters, sizeof(memory->mbcState.pocketCam.registers)); + break; case GB_MMM01: memory->mbcState.mmm01.locked = state->memory.mmm01.locked; memory->mbcState.mmm01.currentBank0 = state->memory.mmm01.bank0; @@ -1005,6 +1015,11 @@ void _pristineCow(struct GB* gb) { if (gb->memory.rom == gb->memory.romBase) { gb->memory.romBase = newRom; } + if (gb->romVf) { + gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->memory.romSize); + gb->romVf->close(gb->romVf); + gb->romVf = NULL; + } gb->memory.rom = newRom; GBMBCSwitchBank(gb, gb->memory.currentBank); gb->isPristine = false; diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index a5e41162f..d157920fa 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -571,20 +571,38 @@ static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer, int y) { } int o = 0; int i; + int16_t ids[GB_VIDEO_MAX_LINE_OBJ]; for (i = 0; i < GB_VIDEO_MAX_OBJ && o < GB_VIDEO_MAX_LINE_OBJ; ++i) { uint8_t oy = renderer->d.oam->obj[i].y; if (y < oy - 16 || y >= oy - 16 + spriteHeight) { continue; } - // TODO: Sort - renderer->obj[o].obj = renderer->d.oam->obj[i]; - renderer->obj[o].index = i; + ids[o] = (renderer->d.oam->obj[i].x << 7) | i; ++o; - if (o == 10) { - break; - } } renderer->objMax = o; + if (renderer->model < GB_MODEL_CGB) { + // Terrble n^2 sort, but it's only 10 elements so it shouldn't be that bad + int16_t ids2[GB_VIDEO_MAX_LINE_OBJ]; + int min = -1; + int j; + for (i = 0; i < o; ++i) { + int min2 = 0xFFFF; + for (j = 0; j < o; ++j) { + if (ids[j] > min && ids[j] < min2) { + min2 = ids[j]; + } + } + min = min2; + ids2[i] = min; + } + memcpy(ids, ids2, sizeof(ids)); + } + for (i = 0; i < o; ++i) { + int id = ids[i] & 0x7F; + renderer->obj[i].obj = renderer->d.oam->obj[id]; + renderer->obj[i].index = id; + } } static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, int startX, int endX, int y) { diff --git a/src/gb/sio.c b/src/gb/sio.c index d327b606d..649213168 100644 --- a/src/gb/sio.c +++ b/src/gb/sio.c @@ -91,11 +91,13 @@ void GBSIOWriteSB(struct GBSIO* sio, uint8_t sb) { void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc) { sio->period = GBSIOCyclesPerTransfer[GBRegisterSCGetClockSpeed(sc)]; // TODO Shift Clock if (GBRegisterSCIsEnable(sc)) { - mTimingDeschedule(&sio->p->timing, &sio->event); if (GBRegisterSCIsShiftClock(sc)) { + mTimingDeschedule(&sio->p->timing, &sio->event); mTimingSchedule(&sio->p->timing, &sio->event, sio->period * (2 - sio->p->doubleSpeed)); sio->remainingBits = 8; } + } else { + mTimingDeschedule(&sio->p->timing, &sio->event); } if (sio->driver) { sio->driver->writeSC(sio->driver, sc); diff --git a/src/gb/video.c b/src/gb/video.c index 3991b0d7e..37c1e3650 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -770,7 +770,10 @@ void GBVideoWriteSTAT(struct GBVideo* video, GBRegisterSTAT value) { if (!GBRegisterLCDCIsEnable(video->p->memory.io[GB_REG_LCDC]) || video->p->model >= GB_MODEL_CGB) { return; } - if (!_statIRQAsserted(oldStat) && video->mode < 3) { + // Writing to STAT on a DMG selects all STAT IRQ types for one cycle. + // However, the signal that the mode 2 IRQ relies on is only high for + // one cycle, which we don't handle yet. TODO: Handle it. + if (!_statIRQAsserted(oldStat) && (video->mode < 2 || GBRegisterSTATIsLYC(video->stat))) { // TODO: variable for the IRQ line value? video->p->memory.io[GB_REG_IF] |= (1 << GB_IRQ_LCDSTAT); GBUpdateIRQs(video->p); diff --git a/src/gba/audio.c b/src/gba/audio.c index 5d7dd347b..fb0e1b62c 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -37,7 +37,7 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) { audio->sampleEvent.callback = _sample; audio->sampleEvent.priority = 0x18; audio->psg.p = NULL; - uint8_t* nr52 = (uint8_t*) &audio->p->memory.io[REG_SOUNDCNT_X >> 1]; + uint8_t* nr52 = (uint8_t*) &audio->p->memory.io[GBA_REG(SOUNDCNT_X)]; #ifdef __BIG_ENDIAN__ ++nr52; #endif @@ -106,6 +106,9 @@ void GBAAudioDeinit(struct GBAAudio* audio) { } void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) { + if (samples > 0x2000) { + samples = 0x2000; + } mCoreSyncLockAudio(audio->p->sync); audio->samples = samples; blip_clear(audio->psg.left); @@ -118,27 +121,34 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED); info->reg = GBADMARegisterSetWidth(info->reg, 1); switch (info->dest) { - case BASE_IO | REG_FIFO_A_LO: + case GBA_BASE_IO | GBA_REG_FIFO_A_LO: audio->chA.dmaSource = number; break; - case BASE_IO | REG_FIFO_B_LO: + case GBA_BASE_IO | GBA_REG_FIFO_B_LO: audio->chB.dmaSource = number; break; default: mLOG(GBA_AUDIO, GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest); return; } - uint32_t source = info->source; - uint32_t magic[2] = { - audio->p->cpu->memory.load32(audio->p->cpu, source - 0x350, NULL), - audio->p->cpu->memory.load32(audio->p->cpu, source - 0x980, NULL) - }; if (audio->mixer) { - if (magic[0] - MP2K_MAGIC <= MP2K_LOCK_MAX) { - audio->mixer->engage(audio->mixer, source - 0x350); - } else if (magic[1] - MP2K_MAGIC <= MP2K_LOCK_MAX) { - audio->mixer->engage(audio->mixer, source - 0x980); - } else { + uint32_t source = info->source; + uint32_t offsets[] = { 0x350, 0x980 }; + size_t i; + for (i = 0; i < sizeof(offsets) / sizeof(*offsets); ++i) { + if (source < GBA_BASE_EWRAM + offsets[i]) { + continue; + } + if (source >= GBA_BASE_IO + offsets[i]) { + continue; + } + uint32_t value = GBALoad32(audio->p->cpu, source - offsets[i], NULL); + if (value - MP2K_MAGIC <= MP2K_LOCK_MAX) { + audio->mixer->engage(audio->mixer, source - offsets[i]); + break; + } + } + if (i == sizeof(offsets) / sizeof(*offsets)) { audio->externalMixing = false; } } @@ -231,16 +241,36 @@ void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) { } void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) { + GBAAudioSample(audio, mTimingCurrentTime(&audio->p->timing)); audio->enable = GBAudioEnableGetEnable(value); GBAudioWriteNR52(&audio->psg, value); + if (!audio->enable) { + int i; + for (i = GBA_REG_SOUND1CNT_LO; i < GBA_REG_SOUNDCNT_HI; i += 2) { + audio->p->memory.io[i >> 1] = 0; + } + audio->psg.ch3.size = 0; + audio->psg.ch3.bank = 0; + audio->psg.ch3.volume = 0; + audio->volume = 0; + audio->volumeChA = 0; + audio->volumeChB = 0; + audio->p->memory.io[GBA_REG(SOUNDCNT_HI)] &= 0xFF00; + } } void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value) { + int32_t timestamp = mTimingCurrentTime(&audio->p->timing); + GBAAudioSample(audio, timestamp); audio->soundbias = value; int32_t oldSampleInterval = audio->sampleInterval; audio->sampleInterval = 0x200 >> GBARegisterSOUNDBIASGetResolution(value); - if (oldSampleInterval != audio->sampleInterval && audio->p->stream && audio->p->stream->audioRateChanged) { - audio->p->stream->audioRateChanged(audio->p->stream, GBA_ARM7TDMI_FREQUENCY / audio->sampleInterval); + if (oldSampleInterval != audio->sampleInterval) { + timestamp -= audio->lastSample; + audio->sampleIndex = timestamp >> (9 - GBARegisterSOUNDBIASGetResolution(value)); + if (audio->p->stream && audio->p->stream->audioRateChanged) { + audio->p->stream->audioRateChanged(audio->p->stream, GBA_ARM7TDMI_FREQUENCY / audio->sampleInterval); + } } } @@ -273,10 +303,10 @@ uint32_t GBAAudioReadWaveRAM(struct GBAAudio* audio, int address) { uint32_t GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) { struct GBAAudioFIFO* channel; switch (address) { - case REG_FIFO_A_LO: + case GBA_REG_FIFO_A_LO: channel = &audio->chA; break; - case REG_FIFO_B_LO: + case GBA_REG_FIFO_B_LO: channel = &audio->chB; break; default: @@ -506,6 +536,16 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) { GBAudioPSGDeserialize(&audio->psg, &state->audio.psg, &state->audio.flags); + uint16_t reg; + LOAD_16(reg, GBA_REG_SOUND1CNT_X, state->io); + GBAIOWrite(audio->p, GBA_REG_SOUND1CNT_X, reg & 0x7FFF); + LOAD_16(reg, GBA_REG_SOUND2CNT_HI, state->io); + GBAIOWrite(audio->p, GBA_REG_SOUND2CNT_HI, reg & 0x7FFF); + LOAD_16(reg, GBA_REG_SOUND3CNT_X, state->io); + GBAIOWrite(audio->p, GBA_REG_SOUND3CNT_X, reg & 0x7FFF); + LOAD_16(reg, GBA_REG_SOUND4CNT_HI, state->io); + GBAIOWrite(audio->p, GBA_REG_SOUND4CNT_HI, reg & 0x7FFF); + LOAD_32(audio->chA.internalSample, 0, &state->audio.internalA); LOAD_32(audio->chB.internalSample, 0, &state->audio.internalB); memcpy(audio->chA.samples, state->samples.chA, sizeof(audio->chA.samples)); diff --git a/src/gba/bios.c b/src/gba/bios.c index b7c4a49ec..3eddbe6d9 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -49,11 +49,11 @@ static void _SoftReset(struct GBA* gba) { cpu->gprs[ARM_LR] = 0; cpu->gprs[ARM_SP] = GBA_SP_BASE_SYSTEM; int8_t flag = ((int8_t*) gba->memory.iwram)[0x7FFA]; - memset(((int8_t*) gba->memory.iwram) + SIZE_WORKING_IRAM - 0x200, 0, 0x200); + memset(((int8_t*) gba->memory.iwram) + GBA_SIZE_IWRAM - 0x200, 0, 0x200); if (flag) { - cpu->gprs[ARM_PC] = BASE_WORKING_RAM; + cpu->gprs[ARM_PC] = GBA_BASE_EWRAM; } else { - cpu->gprs[ARM_PC] = BASE_CART0; + cpu->gprs[ARM_PC] = GBA_BASE_ROM0; } _ARMSetMode(cpu, MODE_ARM); ARMWritePC(cpu); @@ -62,126 +62,126 @@ static void _SoftReset(struct GBA* gba) { static void _RegisterRamReset(struct GBA* gba) { uint32_t registers = gba->cpu->gprs[0]; struct ARMCore* cpu = gba->cpu; - cpu->memory.store16(cpu, BASE_IO | REG_DISPCNT, 0x0080, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DISPCNT, 0x0080, 0); if (registers & 0x01) { - memset(gba->memory.wram, 0, SIZE_WORKING_RAM); + memset(gba->memory.wram, 0, GBA_SIZE_EWRAM); } if (registers & 0x02) { - memset(gba->memory.iwram, 0, SIZE_WORKING_IRAM - 0x200); + memset(gba->memory.iwram, 0, GBA_SIZE_IWRAM - 0x200); } if (registers & 0x04) { - memset(gba->video.palette, 0, SIZE_PALETTE_RAM); + memset(gba->video.palette, 0, GBA_SIZE_PALETTE_RAM); } if (registers & 0x08) { - memset(gba->video.vram, 0, SIZE_VRAM); + memset(gba->video.vram, 0, GBA_SIZE_VRAM); } if (registers & 0x10) { - memset(gba->video.oam.raw, 0, SIZE_OAM); + memset(gba->video.oam.raw, 0, GBA_SIZE_OAM); } if (registers & 0x20) { - cpu->memory.store16(cpu, BASE_IO | REG_SIOCNT, 0x0000, 0); - cpu->memory.store16(cpu, BASE_IO | REG_RCNT, RCNT_INITIAL, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SIOMLT_SEND, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_JOYCNT, 0, 0); - cpu->memory.store32(cpu, BASE_IO | REG_JOY_RECV_LO, 0, 0); - cpu->memory.store32(cpu, BASE_IO | REG_JOY_TRANS_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SIOCNT, 0x0000, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_RCNT, RCNT_INITIAL, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SIOMLT_SEND, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_JOYCNT, 0, 0); + cpu->memory.store32(cpu, GBA_BASE_IO | GBA_REG_JOY_RECV_LO, 0, 0); + cpu->memory.store32(cpu, GBA_BASE_IO | GBA_REG_JOY_TRANS_LO, 0, 0); } if (registers & 0x40) { - cpu->memory.store16(cpu, BASE_IO | REG_SOUND1CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND1CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND1CNT_X, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND2CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND2CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND3CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND3CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND3CNT_X, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND4CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUND4CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUNDCNT_X, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_SOUNDBIAS, 0x200, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND1CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND1CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND1CNT_X, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND2CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND2CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND3CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND3CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND3CNT_X, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND4CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUND4CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUNDCNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUNDCNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUNDCNT_X, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_SOUNDBIAS, 0x200, 0); memset(gba->audio.psg.ch3.wavedata32, 0, sizeof(gba->audio.psg.ch3.wavedata32)); } if (registers & 0x80) { - cpu->memory.store16(cpu, BASE_IO | REG_DISPSTAT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_VCOUNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG0CNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG1CNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2CNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3CNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG0HOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG0VOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG1HOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG1VOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2HOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2VOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3HOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3VOFS, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2PA, 0x100, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2PB, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2PC, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG2PD, 0x100, 0); - cpu->memory.store32(cpu, BASE_IO | REG_BG2X_LO, 0, 0); - cpu->memory.store32(cpu, BASE_IO | REG_BG2Y_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3PA, 0x100, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3PB, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3PC, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BG3PD, 0x100, 0); - cpu->memory.store32(cpu, BASE_IO | REG_BG3X_LO, 0, 0); - cpu->memory.store32(cpu, BASE_IO | REG_BG3Y_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WIN0H, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WIN1H, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WIN0V, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WIN1V, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WININ, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WINOUT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_MOSAIC, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BLDCNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BLDALPHA, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_BLDY, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA0SAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA0SAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA0DAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA0DAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA0CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA0CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA1SAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA1SAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA1DAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA1DAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA1CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA1CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA2SAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA2SAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA2DAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA2DAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA2CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA2CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA3SAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA3SAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA3DAD_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA3DAD_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA3CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_DMA3CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM0CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM0CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM1CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM1CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM2CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM2CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM3CNT_LO, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_TM3CNT_HI, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_IE, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_IF, 0xFFFF, 0); - cpu->memory.store16(cpu, BASE_IO | REG_WAITCNT, 0, 0); - cpu->memory.store16(cpu, BASE_IO | REG_IME, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DISPSTAT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_VCOUNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG0CNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG1CNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2CNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3CNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG0HOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG0VOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG1HOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG1VOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2HOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2VOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3HOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3VOFS, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2PA, 0x100, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2PB, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2PC, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG2PD, 0x100, 0); + cpu->memory.store32(cpu, GBA_BASE_IO | GBA_REG_BG2X_LO, 0, 0); + cpu->memory.store32(cpu, GBA_BASE_IO | GBA_REG_BG2Y_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3PA, 0x100, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3PB, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3PC, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BG3PD, 0x100, 0); + cpu->memory.store32(cpu, GBA_BASE_IO | GBA_REG_BG3X_LO, 0, 0); + cpu->memory.store32(cpu, GBA_BASE_IO | GBA_REG_BG3Y_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WIN0H, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WIN1H, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WIN0V, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WIN1V, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WININ, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WINOUT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_MOSAIC, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BLDCNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BLDALPHA, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_BLDY, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA0SAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA0SAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA0DAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA0DAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA0CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA0CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA1SAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA1SAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA1DAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA1DAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA1CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA1CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA2SAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA2SAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA2DAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA2DAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA2CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA2CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA3SAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA3SAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA3DAD_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA3DAD_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA3CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_DMA3CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM0CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM0CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM1CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM1CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM2CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM2CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM3CNT_LO, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_TM3CNT_HI, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_IE, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_IF, 0xFFFF, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_WAITCNT, 0, 0); + cpu->memory.store16(cpu, GBA_BASE_IO | GBA_REG_IME, 0, 0); } if (registers & 0x9C) { gba->video.renderer->reset(gba->video.renderer); - gba->video.renderer->writeVideoRegister(gba->video.renderer, REG_DISPCNT, gba->memory.io[REG_DISPCNT >> 1]); + gba->video.renderer->writeVideoRegister(gba->video.renderer, GBA_REG_DISPCNT, gba->memory.io[GBA_REG(DISPCNT)]); int i; - for (i = REG_BG0CNT; i < REG_SOUND1CNT_LO; i += 2) { + for (i = GBA_REG_BG0CNT; i < GBA_REG_SOUND1CNT_LO; i += 2) { gba->video.renderer->writeVideoRegister(gba->video.renderer, i, gba->memory.io[i >> 1]); } } @@ -275,7 +275,7 @@ static void _MidiKey2Freq(struct GBA* gba) { struct ARMCore* cpu = gba->cpu; int oldRegion = gba->memory.activeRegion; - gba->memory.activeRegion = REGION_BIOS; + gba->memory.activeRegion = GBA_REGION_BIOS; uint32_t key = cpu->memory.load32(cpu, cpu->gprs[0] + 4, 0); gba->memory.activeRegion = oldRegion; @@ -494,7 +494,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { break; case GBA_SWI_CPU_SET: case GBA_SWI_CPU_FAST_SET: - if (cpu->gprs[0] >> BASE_OFFSET < REGION_WORKING_RAM) { + if (cpu->gprs[0] >> BASE_OFFSET < GBA_REGION_EWRAM) { mLOG(GBA_BIOS, GAME_ERROR, "Cannot CpuSet from BIOS"); break; } @@ -509,7 +509,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { case GBA_SWI_GET_BIOS_CHECKSUM: cpu->gprs[0] = GBA_BIOS_CHECKSUM; cpu->gprs[1] = 1; - cpu->gprs[3] = SIZE_BIOS; + cpu->gprs[3] = GBA_SIZE_BIOS; break; case GBA_SWI_BG_AFFINE_SET: _BgAffineSet(gba); @@ -518,7 +518,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { _ObjAffineSet(gba); break; case GBA_SWI_BIT_UNPACK: - if (cpu->gprs[0] < BASE_WORKING_RAM) { + if (cpu->gprs[0] < GBA_BASE_EWRAM) { mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source"); break; } @@ -526,9 +526,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { default: mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack destination"); // Fall through - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_VRAM: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_VRAM: _unBitPack(gba); break; } @@ -543,9 +543,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { default: mLOG(GBA_BIOS, GAME_ERROR, "Bad LZ77 destination"); // Fall through - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_VRAM: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_VRAM: useStall = true; _unLz77(gba, immediate == GBA_SWI_LZ77_UNCOMP_WRAM ? 1 : 2); break; @@ -560,9 +560,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { default: mLOG(GBA_BIOS, GAME_ERROR, "Bad Huffman destination"); // Fall through - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_VRAM: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_VRAM: _unHuffman(gba); break; } @@ -577,9 +577,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { default: mLOG(GBA_BIOS, GAME_ERROR, "Bad RL destination"); // Fall through - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_VRAM: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_VRAM: _unRl(gba, immediate == GBA_SWI_RL_UNCOMP_WRAM ? 1 : 2); break; } @@ -595,9 +595,9 @@ void GBASwi16(struct ARMCore* cpu, int immediate) { default: mLOG(GBA_BIOS, GAME_ERROR, "Bad UnFilter destination"); // Fall through - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_VRAM: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_VRAM: _unFilter(gba, immediate == GBA_SWI_DIFF_16BIT_UNFILTER ? 2 : 1, immediate == GBA_SWI_DIFF_8BIT_UNFILTER_WRAM ? 1 : 2); break; } diff --git a/src/gba/cart/ereader.c b/src/gba/cart/ereader.c index 030e0d183..6a3ce58b0 100644 --- a/src/gba/cart/ereader.c +++ b/src/gba/cart/ereader.c @@ -13,7 +13,7 @@ #ifdef USE_FFMPEG #include #ifdef USE_PNG -#include +#include #include #endif @@ -888,7 +888,11 @@ struct EReaderScan* EReaderScanLoadImagePNG(const char* filename) { } png_infop info = png_create_info_struct(png); png_infop end = png_create_info_struct(png); - PNGReadHeader(png, info); + if (!PNGReadHeader(png, info)) { + PNGReadClose(png, info, end); + vf->close(vf); + return NULL; + } unsigned height = png_get_image_height(png, info); unsigned width = png_get_image_width(png, info); int type = png_get_color_type(png, info); @@ -900,19 +904,34 @@ struct EReaderScan* EReaderScanLoadImagePNG(const char* filename) { break; } image = malloc(height * width * 3); - PNGReadPixels(png, info, image, width, height, width); + if (!image) { + goto out; + } + if (!PNGReadPixels(png, info, image, width, height, width)) { + free(image); + image = NULL; + goto out; + } break; case PNG_COLOR_TYPE_RGBA: if (depth != 8) { break; } image = malloc(height * width * 4); - PNGReadPixelsA(png, info, image, width, height, width); + if (!image) { + goto out; + } + if (!PNGReadPixelsA(png, info, image, width, height, width)) { + free(image); + image = NULL; + goto out; + } break; default: break; } PNGReadFooter(png, end); +out: PNGReadClose(png, info, end); vf->close(vf); if (!image) { @@ -1480,7 +1499,7 @@ bool EReaderScanCard(struct EReaderScan* scan) { size_t i; for (i = 0; i < blocks; ++i) { EReaderScanDetectBlockThreshold(scan, i); - int errors = 36 * 36; + unsigned errors = 36 * 36; while (!EReaderScanScanBlock(scan, i, true)) { if (errors < EReaderBlockListGetPointer(&scan->blocks, i)->errors) { return false; diff --git a/src/gba/cart/gpio.c b/src/gba/cart/gpio.c index 0bb7f3429..53c14dafd 100644 --- a/src/gba/cart/gpio.c +++ b/src/gba/cart/gpio.c @@ -374,7 +374,9 @@ void _lightReadPins(struct GBACartridgeHardware* hw) { mLOG(GBA_HW, DEBUG, "[SOLAR] Got reset"); hw->lightCounter = 0; if (lux) { - lux->sample(lux); + if (lux->sample) { + lux->sample(lux); + } hw->lightSample = lux->readLuminance(lux); } else { hw->lightSample = 0xFF; @@ -421,8 +423,8 @@ void GBAHardwareTiltWrite(struct GBACartridgeHardware* hw, uint32_t address, uin int32_t x = rotationSource->readTiltX(rotationSource); int32_t y = rotationSource->readTiltY(rotationSource); // Normalize to ~12 bits, focused on 0x3A0 - hw->tiltX = (x >> 21) + 0x3A0; // Crop off an extra bit so that we can't go negative - hw->tiltY = (y >> 21) + 0x3A0; + hw->tiltX = 0x3A0 - (x >> 22); + hw->tiltY = 0x3A0 - (y >> 22); } else { mLOG(GBA_HW, GAME_ERROR, "Tilt sensor wrote wrong byte to %04x: %02x", address, value); } @@ -522,7 +524,7 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer LOAD_32(when, 0, &state->hw.gbpNextEvent); if (hw->devices & HW_GB_PLAYER) { GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, SIO_NORMAL_32); - if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) { + if (hw->p->memory.io[GBA_REG(SIOCNT)] & 0x0080) { mTimingSchedule(&hw->p->timing, &hw->p->sio.gbp.event, when); } } diff --git a/src/gba/cart/vfame.c b/src/gba/cart/vfame.c index 57b6d903b..aedcf5d3e 100644 --- a/src/gba/cart/vfame.c +++ b/src/gba/cart/vfame.c @@ -246,7 +246,7 @@ void GBAVFameSramWrite(struct GBAVFameCart* cart, uint32_t address, uint8_t valu // if mode has been set - the address and value of the SRAM write will be modified address = _modifySramAddress(cart->cartType, address, cart->sramMode); value = _modifySramValue(cart->cartType, value, cart->sramMode); - address &= (SIZE_CART_SRAM - 1); + address &= (GBA_SIZE_SRAM - 1); sramData[address] = value; } diff --git a/src/gba/cheats.c b/src/gba/cheats.c index 04082d48a..d055194be 100644 --- a/src/gba/cheats.c +++ b/src/gba/cheats.c @@ -323,49 +323,49 @@ static void GBACheatDumpDirectives(struct mCheatSet* set, struct StringList* dir int GBACheatAddressIsReal(uint32_t address) { switch (address >> BASE_OFFSET) { - case REGION_BIOS: + case GBA_REGION_BIOS: return -0x80; break; - case REGION_WORKING_RAM: - if ((address & OFFSET_MASK) > SIZE_WORKING_RAM) { + case GBA_REGION_EWRAM: + if ((address & OFFSET_MASK) > GBA_SIZE_EWRAM) { return -0x40; } return 0x20; - case REGION_WORKING_IRAM: - if ((address & OFFSET_MASK) > SIZE_WORKING_IRAM) { + case GBA_REGION_IWRAM: + if ((address & OFFSET_MASK) > GBA_SIZE_IWRAM) { return -0x40; } return 0x20; - case REGION_IO: - if ((address & OFFSET_MASK) > SIZE_IO) { + case GBA_REGION_IO: + if ((address & OFFSET_MASK) > GBA_SIZE_IO) { return -0x80; } return 0x10; - case REGION_OAM: - if ((address & OFFSET_MASK) > SIZE_OAM) { + case GBA_REGION_OAM: + if ((address & OFFSET_MASK) > GBA_SIZE_OAM) { return -0x80; } return -0x8; - case REGION_VRAM: - if ((address & OFFSET_MASK) > SIZE_VRAM) { + case GBA_REGION_VRAM: + if ((address & OFFSET_MASK) > GBA_SIZE_VRAM) { return -0x80; } return -0x8; - case REGION_PALETTE_RAM: - if ((address & OFFSET_MASK) > SIZE_PALETTE_RAM) { + case GBA_REGION_PALETTE_RAM: + if ((address & OFFSET_MASK) > GBA_SIZE_PALETTE_RAM) { return -0x80; } return -0x8; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: return -0x8; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: - if ((address & OFFSET_MASK) > SIZE_CART_FLASH512) { + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: + if ((address & OFFSET_MASK) > GBA_SIZE_FLASH512) { return -0x80; } return -0x8; diff --git a/src/gba/cheats/codebreaker.c b/src/gba/cheats/codebreaker.c index 0ba5c80ea..1cf2f853b 100644 --- a/src/gba/cheats/codebreaker.c +++ b/src/gba/cheats/codebreaker.c @@ -215,7 +215,7 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o return false; } cheats->hook = malloc(sizeof(*cheats->hook)); - cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1)); + cheats->hook->address = GBA_BASE_ROM0 | (op1 & (GBA_SIZE_ROM0 - 1)); cheats->hook->mode = MODE_THUMB; cheats->hook->refs = 1; cheats->hook->reentries = 0; @@ -278,7 +278,7 @@ bool GBACheatAddCodeBreaker(struct GBACheatSet* cheats, uint32_t op1, uint16_t o cheat = mCheatListAppend(&cheats->d.list); cheat->type = CHEAT_IF_NAND; cheat->width = 2; - cheat->address = BASE_IO | REG_KEYINPUT; + cheat->address = GBA_BASE_IO | GBA_REG_KEYINPUT; cheat->operand = op2; cheat->repeat = 1; return true; diff --git a/src/gba/cheats/gameshark.c b/src/gba/cheats/gameshark.c index 88f48ab49..72071d962 100644 --- a/src/gba/cheats/gameshark.c +++ b/src/gba/cheats/gameshark.c @@ -150,7 +150,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t break; case GSA_PATCH: romPatch = mCheatPatchListAppend(&cheats->d.romPatches); - romPatch->address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1); + romPatch->address = GBA_BASE_ROM0 | ((op1 & 0xFFFFFF) << 1); romPatch->value = op2; romPatch->applied = false; romPatch->width = 2; @@ -207,7 +207,7 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t return false; } cheats->hook = malloc(sizeof(*cheats->hook)); - cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 1)); + cheats->hook->address = GBA_BASE_ROM0 | (op1 & (GBA_SIZE_ROM0 - 1)); cheats->hook->mode = MODE_THUMB; cheats->hook->refs = 1; cheats->hook->reentries = 0; diff --git a/src/gba/cheats/parv3.c b/src/gba/cheats/parv3.c index 30cc5515b..e254ac94d 100644 --- a/src/gba/cheats/parv3.c +++ b/src/gba/cheats/parv3.c @@ -233,7 +233,7 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) { } if (romPatch >= 0) { struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->d.romPatches); - patch->address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1); + patch->address = GBA_BASE_ROM0 | ((op2 & 0xFFFFFF) << 1); patch->applied = false; patch->check = false; patch->width = 2; @@ -282,7 +282,7 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin return false; } cheats->hook = malloc(sizeof(*cheats->hook)); - cheats->hook->address = BASE_CART0 | (op1 & (SIZE_CART0 - 2)); + cheats->hook->address = GBA_BASE_ROM0 | (op1 & (GBA_SIZE_ROM0 - 2)); cheats->hook->mode = MODE_THUMB; cheats->hook->refs = 1; cheats->hook->reentries = 0; @@ -320,7 +320,7 @@ bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uin case PAR3_BASE_OTHER: width = ((op1 >> 24) & 1) + 1; cheat->type = CHEAT_ASSIGN; - cheat->address = BASE_IO | (op1 & OFFSET_MASK); + cheat->address = GBA_BASE_IO | (op1 & OFFSET_MASK); break; } if (op1 & 0x01000000 && (op1 & 0xFE000000) != 0xC6000000) { diff --git a/src/gba/core.c b/src/gba/core.c index a50c11175..46ad70f08 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #ifndef DISABLE_THREADING #include @@ -57,76 +57,110 @@ static const struct mCoreChannelInfo _GBAAudioChannels[] = { static const struct mCoreMemoryBlock _GBAMemoryBlocks[] = { { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, - { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, }; static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM[] = { { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, - { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART_SRAM, "sram", "SRAM", "Static RAM (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_SRAM, SIZE_CART_SRAM, true }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_SRAM, "sram", "SRAM", "Static RAM (32kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_SRAM, GBA_SIZE_SRAM, true }, +}; + +static const struct mCoreMemoryBlock _GBAMemoryBlocksSRAM512[] = { + { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_SRAM, "sram", "SRAM", "Static RAM (64kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_SRAM512, GBA_SIZE_SRAM512, true }, }; static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash512[] = { { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, - { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_SRAM, "sram", "Flash", "Flash Memory (64kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_FLASH512, GBA_SIZE_FLASH512, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, }; static const struct mCoreMemoryBlock _GBAMemoryBlocksFlash1M[] = { { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, - { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART_SRAM, "sram", "Flash", "Flash Memory (64kiB)", BASE_CART_SRAM, BASE_CART_SRAM + SIZE_CART_FLASH512, SIZE_CART_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1 }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_SRAM, "sram", "Flash", "Flash Memory (128kiB)", GBA_BASE_SRAM, GBA_BASE_SRAM + GBA_SIZE_FLASH512, GBA_SIZE_FLASH1M, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED, 1, GBA_BASE_SRAM }, }; static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM[] = { { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, - { REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", BASE_BIOS, SIZE_BIOS, SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_RAM, "wram", "EWRAM", "Working RAM (256kiB)", BASE_WORKING_RAM, BASE_WORKING_RAM + SIZE_WORKING_RAM, SIZE_WORKING_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_WORKING_IRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", BASE_WORKING_IRAM, BASE_WORKING_IRAM + SIZE_WORKING_IRAM, SIZE_WORKING_IRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_IO, "io", "MMIO", "Memory-Mapped I/O", BASE_IO, BASE_IO + SIZE_IO, SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", BASE_PALETTE_RAM, BASE_PALETTE_RAM + SIZE_PALETTE_RAM, SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", BASE_VRAM, BASE_VRAM + SIZE_VRAM, SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", BASE_OAM, BASE_OAM + SIZE_OAM, SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, - { REGION_CART0, "cart0", "ROM", "Game Pak (32MiB)", BASE_CART0, BASE_CART0 + SIZE_CART0, SIZE_CART0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", BASE_CART1, BASE_CART1 + SIZE_CART1, SIZE_CART1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", BASE_CART2, BASE_CART2 + SIZE_CART2, SIZE_CART2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, - { REGION_CART_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, SIZE_CART_EEPROM, SIZE_CART_EEPROM, mCORE_MEMORY_RW }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (8kiB)", 0, GBA_SIZE_EEPROM, GBA_SIZE_EEPROM, mCORE_MEMORY_RW }, +}; + +static const struct mCoreMemoryBlock _GBAMemoryBlocksEEPROM512[] = { + { -1, "mem", "All", "All", 0, 0x10000000, 0x10000000, mCORE_MEMORY_VIRTUAL }, + { GBA_REGION_BIOS, "bios", "BIOS", "BIOS (16kiB)", GBA_BASE_BIOS, GBA_SIZE_BIOS, GBA_SIZE_BIOS, mCORE_MEMORY_READ | mCORE_MEMORY_MAPPED }, + { GBA_REGION_EWRAM, "wram", "EWRAM", "Working RAM (256kiB)", GBA_BASE_EWRAM, GBA_BASE_EWRAM + GBA_SIZE_EWRAM, GBA_SIZE_EWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IWRAM, "iwram", "IWRAM", "Internal Working RAM (32kiB)", GBA_BASE_IWRAM, GBA_BASE_IWRAM + GBA_SIZE_IWRAM, GBA_SIZE_IWRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_IO, "io", "MMIO", "Memory-Mapped I/O", GBA_BASE_IO, GBA_BASE_IO + GBA_SIZE_IO, GBA_SIZE_IO, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_PALETTE_RAM, "palette", "Palette", "Palette RAM (1kiB)", GBA_BASE_PALETTE_RAM, GBA_BASE_PALETTE_RAM + GBA_SIZE_PALETTE_RAM, GBA_SIZE_PALETTE_RAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_VRAM, "vram", "VRAM", "Video RAM (96kiB)", GBA_BASE_VRAM, GBA_BASE_VRAM + GBA_SIZE_VRAM, GBA_SIZE_VRAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_OAM, "oam", "OAM", "OBJ Attribute Memory (1kiB)", GBA_BASE_OAM, GBA_BASE_OAM + GBA_SIZE_OAM, GBA_SIZE_OAM, mCORE_MEMORY_RW | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM0, "cart0", "ROM", "Game Pak (32MiB)", GBA_BASE_ROM0, GBA_BASE_ROM0 + GBA_SIZE_ROM0, GBA_SIZE_ROM0, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM1, "cart1", "ROM WS1", "Game Pak (Waitstate 1)", GBA_BASE_ROM1, GBA_BASE_ROM1 + GBA_SIZE_ROM1, GBA_SIZE_ROM1, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_ROM2, "cart2", "ROM WS2", "Game Pak (Waitstate 2)", GBA_BASE_ROM2, GBA_BASE_ROM2 + GBA_SIZE_ROM2, GBA_SIZE_ROM2, mCORE_MEMORY_READ | mCORE_MEMORY_WORM | mCORE_MEMORY_MAPPED }, + { GBA_REGION_SRAM_MIRROR, "eeprom", "EEPROM", "EEPROM (512B)", 0, GBA_SIZE_EEPROM, GBA_SIZE_EEPROM512, mCORE_MEMORY_RW }, +}; + +static const struct mCoreScreenRegion _GBAScreenRegions[] = { + { 0, "Screen", 0, 0, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS } }; static const struct mCoreRegisterInfo _GBARegisters[] = { @@ -178,11 +212,40 @@ struct GBACore { #endif struct mCPUComponent* components[CPU_COMPONENT_MAX]; const struct Configuration* overrides; + struct GBACartridgeOverride override; + bool hasOverride; struct mDebuggerPlatform* debuggerPlatform; struct mCheatDevice* cheatDevice; struct GBAAudioMixer* audioMixer; + struct mCoreMemoryBlock memoryBlocks[12]; + size_t nMemoryBlocks; + int memoryBlockType; }; +#define _MAX(A, B) ((A > B) ? (A) : (B)) +static_assert(sizeof(((struct GBACore*) 0)->memoryBlocks) >= + _MAX( + _MAX( + _MAX( + sizeof(_GBAMemoryBlocksSRAM), + sizeof(_GBAMemoryBlocksSRAM512) + ), + _MAX( + sizeof(_GBAMemoryBlocksFlash512), + sizeof(_GBAMemoryBlocksFlash1M) + ) + ), + _MAX( + _MAX( + sizeof(_GBAMemoryBlocksEEPROM), + sizeof(_GBAMemoryBlocksEEPROM512) + ), + sizeof(_GBAMemoryBlocks) + ) + ), + "GBACore memoryBlocks sized too small"); +#undef _MAX + static bool _GBACoreInit(struct mCore* core) { struct GBACore* gbacore = (struct GBACore*) core; @@ -199,6 +262,7 @@ static bool _GBACoreInit(struct mCore* core) { core->debugger = NULL; core->symbolTable = NULL; core->videoLogger = NULL; + gbacore->hasOverride = false; gbacore->overrides = NULL; gbacore->debuggerPlatform = NULL; gbacore->cheatDevice = NULL; @@ -422,19 +486,51 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c } } -static void _GBACoreDesiredVideoDimensions(const struct mCore* core, unsigned* width, unsigned* height) { +static void _GBACoreSetOverride(struct mCore* core, const void* override) { + struct GBACore* gbacore = (struct GBACore*) core; + memcpy(&gbacore->override, override, sizeof(gbacore->override)); + gbacore->hasOverride = true; +} + +static void _GBACoreBaseVideoSize(const struct mCore* core, unsigned* width, unsigned* height) { + UNUSED(core); + *width = GBA_VIDEO_HORIZONTAL_PIXELS; + *height = GBA_VIDEO_VERTICAL_PIXELS; +} + +static void _GBACoreCurrentVideoSize(const struct mCore* core, unsigned* width, unsigned* height) { + int scale = 1; #ifdef BUILD_GLES3 const struct GBACore* gbacore = (const struct GBACore*) core; - int scale = gbacore->glRenderer.scale; + if (gbacore->glRenderer.outputTex != (unsigned) -1) { + scale = gbacore->glRenderer.scale; + } #else UNUSED(core); - int scale = 1; #endif *width = GBA_VIDEO_HORIZONTAL_PIXELS * scale; *height = GBA_VIDEO_VERTICAL_PIXELS * scale; } +static unsigned _GBACoreVideoScale(const struct mCore* core) { +#ifdef BUILD_GLES3 + const struct GBACore* gbacore = (const struct GBACore*) core; + if (gbacore->glRenderer.outputTex != (unsigned) -1) { + return gbacore->glRenderer.scale; + } +#else + UNUSED(core); +#endif + return 1; +} + +static size_t _GBACoreScreenRegions(const struct mCore* core, const struct mCoreScreenRegion** regions) { + UNUSED(core); + *regions = _GBAScreenRegions; + return 1; +} + static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t stride) { struct GBACore* gbacore = (struct GBACore*) core; gbacore->renderer.outputBuffer = buffer; @@ -500,7 +596,7 @@ static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { gba->stream = stream; if (stream && stream->videoDimensionsChanged) { unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); stream->videoDimensionsChanged(stream, width, height); } if (stream && stream->audioRateChanged) { @@ -509,10 +605,11 @@ static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { } static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) { + struct GBACore* gbacore = (struct GBACore*) core; #ifdef USE_ELF struct ELF* elf = ELFOpen(vf); if (elf) { - if (GBAVerifyELFEntry(elf, BASE_CART0)) { + if (GBAVerifyELFEntry(elf, GBA_BASE_ROM0)) { GBALoadNull(core->board); } bool success = mCoreLoadELF(core, elf); @@ -526,6 +623,7 @@ static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) { if (GBAIsMB(vf)) { return GBALoadMB(core->board, vf); } + gbacore->memoryBlockType = -2; return GBALoadROM(core->board, vf); } @@ -648,13 +746,18 @@ static void _GBACoreReset(struct mCore* core) { if (!forceGbp) { gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION; } - GBAOverrideApplyDefaults(gba, gbacore->overrides); + if (gbacore->hasOverride) { + GBAOverrideApply(gba, &gbacore->override); + } else { + GBAOverrideApplyDefaults(gba, gbacore->overrides); + } if (forceGbp) { gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION; } if (!vbaBugCompat) { gba->vbaBugCompat = false; } + gbacore->memoryBlockType = -2; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 if (!gba->biosVf && core->opts.useBios) { @@ -684,7 +787,7 @@ static void _GBACoreReset(struct mCore* core) { if (!found) { char path[PATH_MAX]; mCoreConfigDirectory(path, PATH_MAX); - strncat(path, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(path)); + strncat(path, PATH_SEP "gba_bios.bin", PATH_MAX - strlen(path) - 1); bios = VFileOpen(path, O_RDONLY); if (bios && GBAIsBIOS(bios)) { found = true; @@ -814,6 +917,20 @@ static void _GBACoreSetPeripheral(struct mCore* core, int type, void* periph) { } } +static void* _GBACoreGetPeripheral(struct mCore* core, int type) { + struct GBA* gba = core->board; + switch (type) { + case mPERIPH_ROTATION: + return gba->rotationSource; + case mPERIPH_RUMBLE: + return gba->rumble; + case mPERIPH_GBA_LUMINANCE: + return gba->luminanceSource; + default: + return NULL; + } +} + static uint32_t _GBACoreBusRead8(struct mCore* core, uint32_t address) { struct ARMCore* cpu = core->cpu; return cpu->memory.load8(cpu, address, 0); @@ -883,23 +1000,51 @@ static void _GBACoreRawWrite32(struct mCore* core, uint32_t address, int segment size_t _GBACoreListMemoryBlocks(const struct mCore* core, const struct mCoreMemoryBlock** blocks) { const struct GBA* gba = core->board; - switch (gba->memory.savedata.type) { - case SAVEDATA_SRAM: - *blocks = _GBAMemoryBlocksSRAM; - return sizeof(_GBAMemoryBlocksSRAM) / sizeof(*_GBAMemoryBlocksSRAM); - case SAVEDATA_FLASH512: - *blocks = _GBAMemoryBlocksFlash512; - return sizeof(_GBAMemoryBlocksFlash512) / sizeof(*_GBAMemoryBlocksFlash512); - case SAVEDATA_FLASH1M: - *blocks = _GBAMemoryBlocksFlash1M; - return sizeof(_GBAMemoryBlocksFlash1M) / sizeof(*_GBAMemoryBlocksFlash1M); - case SAVEDATA_EEPROM: - *blocks = _GBAMemoryBlocksEEPROM; - return sizeof(_GBAMemoryBlocksEEPROM) / sizeof(*_GBAMemoryBlocksEEPROM); - default: - *blocks = _GBAMemoryBlocks; - return sizeof(_GBAMemoryBlocks) / sizeof(*_GBAMemoryBlocks); + struct GBACore* gbacore = (struct GBACore*) core; + + if (gbacore->memoryBlockType != gba->memory.savedata.type) { + switch (gba->memory.savedata.type) { + case SAVEDATA_SRAM: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocksSRAM, sizeof(_GBAMemoryBlocksSRAM)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocksSRAM) / sizeof(*_GBAMemoryBlocksSRAM); + break; + case SAVEDATA_SRAM512: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocksSRAM512, sizeof(_GBAMemoryBlocksSRAM512)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocksSRAM512) / sizeof(*_GBAMemoryBlocksSRAM512); + break; + case SAVEDATA_FLASH512: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocksFlash512, sizeof(_GBAMemoryBlocksFlash512)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocksFlash512) / sizeof(*_GBAMemoryBlocksFlash512); + break; + case SAVEDATA_FLASH1M: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocksFlash1M, sizeof(_GBAMemoryBlocksFlash1M)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocksFlash1M) / sizeof(*_GBAMemoryBlocksFlash1M); + break; + case SAVEDATA_EEPROM: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocksEEPROM, sizeof(_GBAMemoryBlocksEEPROM)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocksEEPROM) / sizeof(*_GBAMemoryBlocksEEPROM); + break; + case SAVEDATA_EEPROM512: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocksEEPROM512, sizeof(_GBAMemoryBlocksEEPROM512)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocksEEPROM512) / sizeof(*_GBAMemoryBlocksEEPROM512); + break; + default: + memcpy(gbacore->memoryBlocks, _GBAMemoryBlocks, sizeof(_GBAMemoryBlocks)); + gbacore->nMemoryBlocks = sizeof(_GBAMemoryBlocks) / sizeof(*_GBAMemoryBlocks); + break; + } + + size_t i; + for (i = 0; i < gbacore->nMemoryBlocks; ++i) { + if (gbacore->memoryBlocks[i].id == GBA_REGION_ROM0 || gbacore->memoryBlocks[i].id == GBA_REGION_ROM1 || gbacore->memoryBlocks[i].id == GBA_REGION_ROM2) { + gbacore->memoryBlocks[i].size = gba->memory.romSize; + } + } + gbacore->memoryBlockType = gba->memory.savedata.type; } + + *blocks = gbacore->memoryBlocks; + return gbacore->nMemoryBlocks; } void* _GBACoreGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) { @@ -907,36 +1052,36 @@ void* _GBACoreGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) { switch (id) { default: return NULL; - case REGION_BIOS: - *sizeOut = SIZE_BIOS; + case GBA_REGION_BIOS: + *sizeOut = GBA_SIZE_BIOS; return gba->memory.bios; - case REGION_WORKING_RAM: - *sizeOut = SIZE_WORKING_RAM; + case GBA_REGION_EWRAM: + *sizeOut = GBA_SIZE_EWRAM; return gba->memory.wram; - case REGION_WORKING_IRAM: - *sizeOut = SIZE_WORKING_IRAM; + case GBA_REGION_IWRAM: + *sizeOut = GBA_SIZE_IWRAM; return gba->memory.iwram; - case REGION_PALETTE_RAM: - *sizeOut = SIZE_PALETTE_RAM; + case GBA_REGION_PALETTE_RAM: + *sizeOut = GBA_SIZE_PALETTE_RAM; return gba->video.palette; - case REGION_VRAM: - *sizeOut = SIZE_VRAM; + case GBA_REGION_VRAM: + *sizeOut = GBA_SIZE_VRAM; return gba->video.vram; - case REGION_OAM: - *sizeOut = SIZE_OAM; + case GBA_REGION_OAM: + *sizeOut = GBA_SIZE_OAM; return gba->video.oam.raw; - case REGION_CART0: - case REGION_CART1: - case REGION_CART2: + case GBA_REGION_ROM0: + case GBA_REGION_ROM1: + case GBA_REGION_ROM2: *sizeOut = gba->memory.romSize; return gba->memory.rom; - case REGION_CART_SRAM: + case GBA_REGION_SRAM: if (gba->memory.savedata.type == SAVEDATA_FLASH1M) { - *sizeOut = SIZE_CART_FLASH1M; + *sizeOut = GBA_SIZE_FLASH1M; return gba->memory.savedata.currentBank; } // Fall through - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM_MIRROR: *sizeOut = GBASavedataSize(&gba->memory.savedata); return gba->memory.savedata.data; } @@ -1099,6 +1244,9 @@ static struct CLIDebuggerSystem* _GBACoreCliDebuggerSystem(struct mCore* core) { } static void _GBACoreAttachDebugger(struct mCore* core, struct mDebugger* debugger) { + if (core->debugger == debugger) { + return; + } if (core->debugger) { GBADetachDebugger(core->board); } @@ -1116,12 +1264,12 @@ static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) { core->symbolTable = mDebuggerSymbolTableCreate(); #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 #ifdef USE_ELF - if (!vf) { + if (!vf && core->dirs.base) { closeAfter = true; vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".elf", O_RDONLY); } #endif - if (!vf) { + if (!vf && core->dirs.base) { closeAfter = true; vf = mDirectorySetOpenSuffix(&core->dirs, core->dirs.base, ".sym", O_RDONLY); } @@ -1150,10 +1298,10 @@ static bool _GBACoreLookupIdentifier(struct mCore* core, const char* name, int32 UNUSED(core); *segment = -1; int i; - for (i = 0; i < REG_MAX; i += 2) { + for (i = 0; i < GBA_REG_MAX; i += 2) { const char* reg = GBAIORegisterNames[i >> 1]; if (reg && strcasecmp(reg, name) == 0) { - *value = BASE_IO | i; + *value = GBA_BASE_IO | i; return true; } } @@ -1321,7 +1469,7 @@ static void _GBACoreStartVideoLog(struct mCore* core, struct mVideoLogContext* c struct GBASerializedState* state = mVideoLogContextInitialState(context, NULL); state->id = 0; - state->cpu.gprs[ARM_PC] = BASE_WORKING_RAM; + state->cpu.gprs[ARM_PC] = GBA_BASE_EWRAM; int channelId = mVideoLoggerAddChannel(context); gbacore->vlProxy.logger = malloc(sizeof(struct mVideoLogger)); @@ -1358,7 +1506,11 @@ struct mCore* GBACoreCreate(void) { core->setSync = _GBACoreSetSync; core->loadConfig = _GBACoreLoadConfig; core->reloadConfigOption = _GBACoreReloadConfigOption; - core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions; + core->setOverride = _GBACoreSetOverride; + core->baseVideoSize = _GBACoreBaseVideoSize; + core->currentVideoSize = _GBACoreCurrentVideoSize; + core->videoScale = _GBACoreVideoScale; + core->screenRegions = _GBACoreScreenRegions; core->setVideoBuffer = _GBACoreSetVideoBuffer; core->setVideoGLTex = _GBACoreSetVideoGLTex; core->getPixels = _GBACoreGetPixels; @@ -1395,6 +1547,7 @@ struct mCore* GBACoreCreate(void) { core->getGameTitle = _GBACoreGetGameTitle; core->getGameCode = _GBACoreGetGameCode; core->setPeripheral = _GBACoreSetPeripheral; + core->getPeripheral = _GBACoreGetPeripheral; core->busRead8 = _GBACoreBusRead8; core->busRead16 = _GBACoreBusRead16; core->busRead32 = _GBACoreBusRead32; @@ -1490,8 +1643,8 @@ static void _GBAVLPReset(struct mCore* core) { // Make sure CPU loop never spins GBAHalt(gba); - gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IME, 0, NULL); - gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IE, 0, NULL); + gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | GBA_REG_IME, 0, NULL); + gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | GBA_REG_IE, 0, NULL); } static bool _GBAVLPLoadROM(struct mCore* core, struct VFile* vf) { @@ -1510,13 +1663,13 @@ static bool _GBAVLPLoadState(struct mCore* core, const void* state) { struct GBA* gba = (struct GBA*) core->board; gba->timing.root = NULL; - gba->cpu->gprs[ARM_PC] = BASE_WORKING_RAM; + gba->cpu->gprs[ARM_PC] = GBA_BASE_EWRAM; gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); // Make sure CPU loop never spins GBAHalt(gba); - gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IME, 0, NULL); - gba->cpu->memory.store16(gba->cpu, BASE_IO | REG_IE, 0, NULL); + gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | GBA_REG_IME, 0, NULL); + gba->cpu->memory.store16(gba->cpu, GBA_BASE_IO | GBA_REG_IE, 0, NULL); GBAVideoDeserialize(&gba->video, state); GBAIODeserialize(gba, state); GBAAudioReset(&gba->audio); diff --git a/src/gba/debugger/cli.c b/src/gba/debugger/cli.c index 5349911ab..8538f4515 100644 --- a/src/gba/debugger/cli.c +++ b/src/gba/debugger/cli.c @@ -3,7 +3,7 @@ * 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 +#include #include #include @@ -56,12 +56,12 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger; if (gbaDebugger->frameAdvance) { - if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1])) { - mDebuggerEnter(&gbaDebugger->d.p->d, DEBUGGER_ENTER_MANUAL, 0); + if (!gbaDebugger->inVblank && GBARegisterDISPSTATIsInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[GBA_REG(DISPSTAT)])) { + mDebuggerEnter(gbaDebugger->d.p->d.p, DEBUGGER_ENTER_MANUAL, 0); gbaDebugger->frameAdvance = false; return false; } - gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]); + gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[GBA_REG(DISPSTAT)]); return true; } return true; @@ -69,11 +69,12 @@ static bool _GBACLIDebuggerCustom(struct CLIDebuggerSystem* debugger) { static void _frame(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { UNUSED(dv); - debugger->d.state = DEBUGGER_CALLBACK; + debugger->d.needsCallback = true; + mDebuggerUpdatePaused(debugger->d.p); struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; gbaDebugger->frameAdvance = true; - gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[REG_DISPSTAT >> 1]); + gbaDebugger->inVblank = GBARegisterDISPSTATGetInVblank(((struct GBA*) gbaDebugger->core->board)->memory.io[GBA_REG(DISPSTAT)]); } #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 diff --git a/src/gba/dma.c b/src/gba/dma.c index e60605b89..11daee2a1 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -33,14 +33,14 @@ void GBADMAReset(struct GBA* gba) { gba->memory.activeDMA = -1; } static bool _isValidDMASAD(int dma, uint32_t address) { - if (dma == 0 && address >= BASE_CART0 && address < BASE_CART_SRAM) { + if (dma == 0 && address >= GBA_BASE_ROM0 && address < GBA_BASE_SRAM) { return false; } - return address >= BASE_WORKING_RAM; + return address >= GBA_BASE_EWRAM; } static bool _isValidDMADAD(int dma, uint32_t address) { - return dma == 3 || address < BASE_CART0; + return dma == 3 || address < GBA_BASE_ROM0; } uint32_t GBADMAWriteSAD(struct GBA* gba, int dma, uint32_t address) { @@ -206,7 +206,7 @@ void _dmaEvent(struct mTiming* timing, void* context, uint32_t cyclesLate) { dma->reg = GBADMARegisterClearEnable(dma->reg); // Clear the enable bit in memory - memory->io[(REG_DMA0CNT_HI + memory->activeDMA * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0; + memory->io[(GBA_REG_DMA0CNT_HI + memory->activeDMA * (GBA_REG_DMA1CNT_HI - GBA_REG_DMA0CNT_HI)) >> 1] &= 0x7FE0; } if (GBADMARegisterGetDestControl(dma->reg) == GBA_DMA_INCREMENT_RELOAD) { dma->nextDest = dma->dest; @@ -278,14 +278,14 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0); } else { - if (sourceRegion == REGION_CART2_EX && (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512)) { + if (sourceRegion == GBA_REGION_ROM2_EX && (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512)) { memory->dmaTransferRegister = GBASavedataReadEEPROM(&memory->savedata); memory->dmaTransferRegister |= memory->dmaTransferRegister << 16; } else if (source) { memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0); memory->dmaTransferRegister |= memory->dmaTransferRegister << 16; } - if (destRegion == REGION_CART2_EX) { + if (destRegion == GBA_REGION_ROM2_EX) { if (memory->savedata.type == SAVEDATA_AUTODETECT) { mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); GBASavedataInitEEPROM(&memory->savedata); @@ -300,7 +300,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { gba->bus = memory->dmaTransferRegister; int sourceOffset; - if (info->nextSource >= BASE_CART0 && info->nextSource < BASE_CART_SRAM && GBADMARegisterGetSrcControl(info->reg) < 3) { + if (info->nextSource >= GBA_BASE_ROM0 && info->nextSource < GBA_BASE_SRAM && GBADMARegisterGetSrcControl(info->reg) < 3) { sourceOffset = width; } else { sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width; @@ -325,7 +325,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { if (!info->nextCount) { info->nextCount |= 0x80000000; - if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { + if (sourceRegion < GBA_REGION_ROM0 || destRegion < GBA_REGION_ROM0) { info->when += 2; } } diff --git a/src/gba/extra/audio-mixer.c b/src/gba/extra/audio-mixer.c index 503fdc8ad..2a14f1ce6 100644 --- a/src/gba/extra/audio-mixer.c +++ b/src/gba/extra/audio-mixer.c @@ -245,9 +245,6 @@ static void _mp2kReload(struct GBAAudioMixer* mixer) { } bool _mp2kEngage(struct GBAAudioMixer* mixer, uint32_t address) { - if (address < BASE_WORKING_RAM) { - return false; - } if (address != mixer->contextAddress) { mixer->contextAddress = address; mixer->p->externalMixing = true; diff --git a/src/gba/extra/battlechip.c b/src/gba/extra/battlechip.c index e87343727..fa6be9796 100644 --- a/src/gba/extra/battlechip.c +++ b/src/gba/extra/battlechip.c @@ -65,16 +65,16 @@ bool GBASIOBattlechipGateLoad(struct GBASIODriver* driver) { uint16_t GBASIOBattlechipGateWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { struct GBASIOBattlechipGate* gate = (struct GBASIOBattlechipGate*) driver; switch (address) { - case REG_SIOCNT: + case GBA_REG_SIOCNT: value &= ~0xC; value |= 0x8; if (value & 0x80) { _battlechipTransfer(gate); } break; - case REG_SIOMLT_SEND: + case GBA_REG_SIOMLT_SEND: break; - case REG_RCNT: + case GBA_REG_RCNT: break; default: break; @@ -98,8 +98,8 @@ void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cycle struct GBASIOBattlechipGate* gate = user; if (gate->d.p->mode == SIO_NORMAL_32) { - gate->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = 0; - gate->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = 0; + gate->d.p->p->memory.io[GBA_REG(SIODATA32_LO)] = 0; + gate->d.p->p->memory.io[GBA_REG(SIODATA32_HI)] = 0; gate->d.p->siocnt = GBASIONormalClearStart(gate->d.p->siocnt); if (GBASIONormalIsIrq(gate->d.p->siocnt)) { GBARaiseIRQ(gate->d.p->p, GBA_IRQ_SIO, cyclesLate); @@ -107,11 +107,11 @@ void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cycle return; } - uint16_t cmd = gate->d.p->p->memory.io[REG_SIOMLT_SEND >> 1]; + uint16_t cmd = gate->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)]; uint16_t reply = 0xFFFF; - gate->d.p->p->memory.io[REG_SIOMULTI0 >> 1] = cmd; - gate->d.p->p->memory.io[REG_SIOMULTI2 >> 1] = 0xFFFF; - gate->d.p->p->memory.io[REG_SIOMULTI3 >> 1] = 0xFFFF; + gate->d.p->p->memory.io[GBA_REG(SIOMULTI0)] = cmd; + gate->d.p->p->memory.io[GBA_REG(SIOMULTI2)] = 0xFFFF; + gate->d.p->p->memory.io[GBA_REG(SIOMULTI3)] = 0xFFFF; gate->d.p->siocnt = GBASIOMultiplayerClearBusy(gate->d.p->siocnt); gate->d.p->siocnt = GBASIOMultiplayerSetId(gate->d.p->siocnt, 0); @@ -191,7 +191,7 @@ void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cycle mLOG(GBA_BATTLECHIP, DEBUG, "Gate: %04X (%i)", reply, gate->state); ++gate->state; - gate->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = reply; + gate->d.p->p->memory.io[GBA_REG(SIOMULTI1)] = reply; if (GBASIOMultiplayerIsIrq(gate->d.p->siocnt)) { GBARaiseIRQ(gate->d.p->p, GBA_IRQ_SIO, cyclesLate); diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index a7f28d153..7842bef1f 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -63,9 +63,9 @@ void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct renderer->logger->parsePacket = _parsePacket; renderer->logger->handleEvent = _handleEvent; renderer->logger->vramBlock = _vramBlock; - renderer->logger->paletteSize = SIZE_PALETTE_RAM; - renderer->logger->vramSize = SIZE_VRAM; - renderer->logger->oamSize = SIZE_OAM; + renderer->logger->paletteSize = GBA_SIZE_PALETTE_RAM; + renderer->logger->vramSize = GBA_SIZE_VRAM; + renderer->logger->oamSize = GBA_SIZE_OAM; renderer->backend = backend; } @@ -82,9 +82,9 @@ static void _init(struct GBAVideoProxyRenderer* proxyRenderer) { } static void _reset(struct GBAVideoProxyRenderer* proxyRenderer) { - memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, SIZE_OAM); - memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, SIZE_PALETTE_RAM); - memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, SIZE_VRAM); + memcpy(proxyRenderer->logger->oam, &proxyRenderer->d.oam->raw, GBA_SIZE_OAM); + memcpy(proxyRenderer->logger->palette, proxyRenderer->d.palette, GBA_SIZE_PALETTE_RAM); + memcpy(proxyRenderer->logger->vram, proxyRenderer->d.vram, GBA_SIZE_VRAM); mVideoLoggerRendererReset(proxyRenderer->logger); } @@ -199,19 +199,19 @@ static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerD proxyRenderer->backend->writeVideoRegister(proxyRenderer->backend, item->address, item->value); break; case DIRTY_PALETTE: - if (item->address < SIZE_PALETTE_RAM) { + if (item->address < GBA_SIZE_PALETTE_RAM) { STORE_16LE(item->value, item->address, logger->palette); proxyRenderer->backend->writePalette(proxyRenderer->backend, item->address, item->value); } break; case DIRTY_OAM: - if (item->address < SIZE_OAM) { + if (item->address < GBA_SIZE_OAM) { STORE_16LE(item->value, item->address << 1, logger->oam); proxyRenderer->backend->writeOAM(proxyRenderer->backend, item->address); } break; case DIRTY_VRAM: - if (item->address <= SIZE_VRAM - 0x1000) { + if (item->address <= GBA_SIZE_VRAM - 0x1000) { logger->readData(logger, &logger->vram[item->address >> 1], 0x1000, true); proxyRenderer->backend->writeVRAM(proxyRenderer->backend, item->address); } else { @@ -243,29 +243,29 @@ static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address) { uint16_t GBAVideoProxyRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) { struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer; switch (address) { - case REG_DISPCNT: + case GBA_REG_DISPCNT: value &= 0xFFF7; break; - case REG_BG0CNT: - case REG_BG1CNT: + case GBA_REG_BG0CNT: + case GBA_REG_BG1CNT: value &= 0xDFFF; break; - case REG_BG2CNT: - case REG_BG3CNT: + case GBA_REG_BG2CNT: + case GBA_REG_BG3CNT: value &= 0xFFFF; break; - case REG_BG0HOFS: - case REG_BG0VOFS: - case REG_BG1HOFS: - case REG_BG1VOFS: - case REG_BG2HOFS: - case REG_BG2VOFS: - case REG_BG3HOFS: - case REG_BG3VOFS: + case GBA_REG_BG0HOFS: + case GBA_REG_BG0VOFS: + case GBA_REG_BG1HOFS: + case GBA_REG_BG1VOFS: + case GBA_REG_BG2HOFS: + case GBA_REG_BG2VOFS: + case GBA_REG_BG3HOFS: + case GBA_REG_BG3VOFS: value &= 0x01FF; break; } - if (address > REG_BLDY) { + if (address > GBA_REG_BLDY) { return value; } if (renderer->cache) { diff --git a/src/gba/gba.c b/src/gba/gba.c index b26ec85af..7586ae66c 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -108,7 +108,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->keyCallback = NULL; mCoreCallbacksListInit(&gba->coreCallbacks, 0); - gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); + gba->biosChecksum = GBAChecksum(gba->memory.bios, GBA_SIZE_BIOS); gba->idleOptimization = IDLE_LOOP_REMOVE; gba->idleLoop = IDLE_LOOP_NONE; @@ -132,12 +132,13 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { } void GBAUnloadROM(struct GBA* gba) { + GBAMemoryClearAGBPrint(gba); if (gba->memory.rom && !gba->isPristine) { if (gba->yankedRomSize) { gba->yankedRomSize = 0; } #ifndef FIXED_ROM_BUFFER - mappedMemoryFree(gba->memory.rom, SIZE_CART0); + mappedMemoryFree(gba->memory.rom, GBA_SIZE_ROM0); #endif } @@ -172,7 +173,7 @@ void GBADestroy(struct GBA* gba) { GBAUnloadMB(gba); if (gba->biosVf) { - gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS); + gba->biosVf->unmap(gba->biosVf, gba->memory.bios, GBA_SIZE_BIOS); gba->biosVf->close(gba->biosVf); gba->biosVf = 0; } @@ -247,7 +248,7 @@ void GBAReset(struct ARMCore* cpu) { if (GBAIsMB(gba->mbVf) && !isELF) { gba->mbVf->seek(gba->mbVf, 0, SEEK_SET); - gba->mbVf->read(gba->mbVf, gba->memory.wram, SIZE_WORKING_RAM); + gba->mbVf->read(gba->mbVf, gba->memory.wram, GBA_SIZE_EWRAM); } gba->lastJump = 0; @@ -259,7 +260,7 @@ void GBAReset(struct ARMCore* cpu) { memset(gba->debugString, 0, sizeof(gba->debugString)); - if (gba->romVf && gba->romVf->size(gba->romVf) > SIZE_CART0) { + if (gba->romVf && gba->romVf->size(gba->romVf) > GBA_SIZE_ROM0) { char ident; gba->romVf->seek(gba->romVf, 0xAC, SEEK_SET); gba->romVf->read(gba->romVf, &ident, 1); @@ -274,17 +275,17 @@ void GBASkipBIOS(struct GBA* gba) { struct ARMCore* cpu = gba->cpu; if (cpu->gprs[ARM_PC] == BASE_RESET + WORD_SIZE_ARM) { if (gba->memory.rom) { - cpu->gprs[ARM_PC] = BASE_CART0; + cpu->gprs[ARM_PC] = GBA_BASE_ROM0; } else if (gba->memory.wram[0x30]) { - cpu->gprs[ARM_PC] = BASE_WORKING_RAM + 0xC0; + cpu->gprs[ARM_PC] = GBA_BASE_EWRAM + 0xC0; } else { - cpu->gprs[ARM_PC] = BASE_WORKING_RAM; + cpu->gprs[ARM_PC] = GBA_BASE_EWRAM; } gba->video.vcount = 0x7E; - gba->memory.io[REG_VCOUNT >> 1] = 0x7E; + gba->memory.io[GBA_REG(VCOUNT)] = 0x7E; mTimingDeschedule(&gba->timing, &gba->video.event); mTimingSchedule(&gba->timing, &gba->video.event, 117); - gba->memory.io[REG_POSTFLG >> 1] = 1; + gba->memory.io[GBA_REG(POSTFLG)] = 1; ARMWritePC(cpu); } } @@ -318,7 +319,7 @@ static void GBAProcessEvents(struct ARMCore* cpu) { cpu->nextEvent = nextEvent; if (cpu->halted) { cpu->cycles = nextEvent; - if (!gba->memory.io[REG_IME >> 1] || !gba->memory.io[REG_IE >> 1]) { + if (!gba->memory.io[GBA_REG(IME)] || !gba->memory.io[GBA_REG(IE)]) { break; } } @@ -360,14 +361,14 @@ bool GBALoadNull(struct GBA* gba) { gba->romVf = NULL; gba->pristineRomSize = 0; #ifndef FIXED_ROM_BUFFER - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); + gba->memory.rom = anonymousMemoryMap(GBA_SIZE_ROM0); #else gba->memory.rom = romBuffer; #endif gba->isPristine = false; gba->yankedRomSize = 0; - gba->memory.romSize = SIZE_CART0; - gba->memory.romMask = SIZE_CART0 - 1; + gba->memory.romSize = GBA_SIZE_ROM0; + gba->memory.romMask = GBA_SIZE_ROM0 - 1; gba->romCrc32 = 0; if (gba->cpu) { @@ -381,9 +382,9 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf) { GBAUnloadMB(gba); gba->mbVf = vf; vf->seek(vf, 0, SEEK_SET); - memset(gba->memory.wram, 0, SIZE_WORKING_RAM); - vf->read(vf, gba->memory.wram, SIZE_WORKING_RAM); - if (gba->cpu && gba->memory.activeRegion == REGION_WORKING_RAM) { + memset(gba->memory.wram, 0, GBA_SIZE_EWRAM); + vf->read(vf, gba->memory.wram, GBA_SIZE_EWRAM); + if (gba->cpu && gba->memory.activeRegion == GBA_REGION_IWRAM) { gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); } return true; @@ -405,7 +406,7 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) { gba->isPristine = true; gba->pristineRomSize = vf->size(vf); vf->seek(vf, 0, SEEK_SET); - if (gba->pristineRomSize > SIZE_CART0) { + if (gba->pristineRomSize > GBA_SIZE_ROM0) { char ident; vf->seek(vf, 0xAC, SEEK_SET); vf->read(vf, &ident, 1); @@ -415,13 +416,13 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) { #ifdef FIXED_ROM_BUFFER gba->memory.rom = romBuffer; #else - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); + gba->memory.rom = anonymousMemoryMap(GBA_SIZE_ROM0); #endif } else { - gba->memory.rom = vf->map(vf, SIZE_CART0, MAP_READ); - gba->memory.romSize = SIZE_CART0; + gba->memory.rom = vf->map(vf, GBA_SIZE_ROM0, MAP_READ); + gba->memory.romSize = GBA_SIZE_ROM0; } - gba->pristineRomSize = SIZE_CART0; + gba->pristineRomSize = GBA_SIZE_ROM0; } else if (gba->pristineRomSize == 0x00100000) { // 1 MiB ROMs (e.g. Classic NES) all appear as 4x mirrored, but not more gba->isPristine = false; @@ -429,7 +430,7 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) { #ifdef FIXED_ROM_BUFFER gba->memory.rom = romBuffer; #else - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); + gba->memory.rom = anonymousMemoryMap(GBA_SIZE_ROM0); #endif vf->read(vf, gba->memory.rom, gba->pristineRomSize); memcpy(&gba->memory.rom[0x40000], gba->memory.rom, 0x00100000); @@ -450,15 +451,15 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) { if (popcount32(gba->memory.romSize) != 1) { // This ROM is either a bad dump or homebrew. Emulate flash cart behavior. #ifndef FIXED_ROM_BUFFER - void* newRom = anonymousMemoryMap(SIZE_CART0); + void* newRom = anonymousMemoryMap(GBA_SIZE_ROM0); memcpy(newRom, gba->memory.rom, gba->pristineRomSize); gba->memory.rom = newRom; #endif - gba->memory.romSize = SIZE_CART0; - gba->memory.romMask = SIZE_CART0 - 1; + gba->memory.romSize = GBA_SIZE_ROM0; + gba->memory.romMask = GBA_SIZE_ROM0 - 1; gba->isPristine = false; } - if (gba->cpu && gba->memory.activeRegion >= REGION_CART0) { + if (gba->cpu && gba->memory.activeRegion >= GBA_REGION_ROM0) { gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]); } GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); @@ -485,23 +486,23 @@ void GBAYankROM(struct GBA* gba) { } void GBALoadBIOS(struct GBA* gba, struct VFile* vf) { - if (vf->size(vf) != SIZE_BIOS) { + if (vf->size(vf) != GBA_SIZE_BIOS) { mLOG(GBA, WARN, "Incorrect BIOS size"); return; } - uint32_t* bios = vf->map(vf, SIZE_BIOS, MAP_READ); + uint32_t* bios = vf->map(vf, GBA_SIZE_BIOS, MAP_READ); if (!bios) { mLOG(GBA, WARN, "Couldn't map BIOS"); return; } if (gba->biosVf) { - gba->biosVf->unmap(gba->biosVf, gba->memory.bios, SIZE_BIOS); + gba->biosVf->unmap(gba->biosVf, gba->memory.bios, GBA_SIZE_BIOS); gba->biosVf->close(gba->biosVf); } gba->biosVf = vf; gba->memory.bios = bios; gba->memory.fullBios = 1; - uint32_t checksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); + uint32_t checksum = GBAChecksum(gba->memory.bios, GBA_SIZE_BIOS); mLOG(GBA, DEBUG, "BIOS Checksum: 0x%X", checksum); if (checksum == GBA_BIOS_CHECKSUM) { mLOG(GBA, INFO, "Official GBA BIOS detected"); @@ -511,7 +512,7 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf) { mLOG(GBA, WARN, "BIOS checksum incorrect"); } gba->biosChecksum = checksum; - if (gba->memory.activeRegion == REGION_BIOS) { + if (gba->memory.activeRegion == GBA_REGION_BIOS) { gba->cpu->memory.activeRegion = gba->memory.bios; } // TODO: error check @@ -519,18 +520,18 @@ void GBALoadBIOS(struct GBA* gba, struct VFile* vf) { void GBAApplyPatch(struct GBA* gba, struct Patch* patch) { size_t patchedSize = patch->outputSize(patch, gba->memory.romSize); - if (!patchedSize || patchedSize > SIZE_CART0) { + if (!patchedSize || patchedSize > GBA_SIZE_ROM0) { return; } - void* newRom = anonymousMemoryMap(SIZE_CART0); + void* newRom = anonymousMemoryMap(GBA_SIZE_ROM0); if (!patch->applyPatch(patch, gba->memory.rom, gba->pristineRomSize, newRom, patchedSize)) { - mappedMemoryFree(newRom, SIZE_CART0); + mappedMemoryFree(newRom, GBA_SIZE_ROM0); return; } if (gba->romVf) { #ifndef FIXED_ROM_BUFFER if (!gba->isPristine) { - mappedMemoryFree(gba->memory.rom, SIZE_CART0); + mappedMemoryFree(gba->memory.rom, GBA_SIZE_ROM0); } else { gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); } @@ -547,7 +548,7 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) { } void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq, uint32_t cyclesLate) { - gba->memory.io[REG_IF >> 1] |= 1 << irq; + gba->memory.io[GBA_REG(IF)] |= 1 << irq; GBATestIRQ(gba, cyclesLate); } @@ -557,7 +558,7 @@ void GBATestIRQNoDelay(struct ARMCore* cpu) { } void GBATestIRQ(struct GBA* gba, uint32_t cyclesLate) { - if (gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) { + if (gba->memory.io[GBA_REG(IE)] & gba->memory.io[GBA_REG(IF)]) { if (!mTimingIsScheduled(&gba->timing, &gba->irqEvent)) { mTimingSchedule(&gba->timing, &gba->irqEvent, GBA_IRQ_DELAY - cyclesLate); } @@ -571,7 +572,7 @@ void GBAHalt(struct GBA* gba) { void GBAStop(struct GBA* gba) { int validIrqs = (1 << GBA_IRQ_GAMEPAK) | (1 << GBA_IRQ_KEYPAD) | (1 << GBA_IRQ_SIO); - int sleep = gba->memory.io[REG_IE >> 1] & validIrqs; + int sleep = gba->memory.io[GBA_REG(IE)] & validIrqs; size_t c; for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); @@ -663,10 +664,9 @@ bool GBAIsROM(struct VFile* vf) { #ifdef USE_ELF struct ELF* elf = ELFOpen(vf); if (elf) { - uint32_t entry = ELFEntry(elf); bool isGBA = true; isGBA = isGBA && ELFMachine(elf) == EM_ARM; - isGBA = isGBA && (GBAVerifyELFEntry(elf, BASE_CART0) || GBAVerifyELFEntry(elf, BASE_WORKING_RAM + 0xC0)); + isGBA = isGBA && (GBAVerifyELFEntry(elf, GBA_BASE_ROM0) || GBAVerifyELFEntry(elf, GBA_BASE_EWRAM + 0xC0)); ELFClose(elf); return isGBA; } @@ -722,12 +722,12 @@ bool GBAIsMB(struct VFile* vf) { #ifdef USE_ELF struct ELF* elf = ELFOpen(vf); if (elf) { - bool isMB = GBAVerifyELFEntry(elf, BASE_WORKING_RAM + 0xC0); + bool isMB = GBAVerifyELFEntry(elf, GBA_BASE_EWRAM + 0xC0); ELFClose(elf); return isMB; } #endif - if (vf->size(vf) > SIZE_WORKING_RAM) { + if (vf->size(vf) > GBA_SIZE_EWRAM) { return false; } if (vf->seek(vf, GBA_MB_MAGIC_OFFSET, SEEK_SET) < 0) { @@ -764,10 +764,10 @@ bool GBAIsMB(struct VFile* vf) { } pc += 4; LOAD_32(opcode, 0, &signature); - if ((opcode & ~0x1FFFF) == BASE_WORKING_RAM) { + if ((opcode & ~0x1FFFF) == GBA_BASE_EWRAM) { ++wramAddrs; } - if ((opcode & ~0x1FFFF) == BASE_CART0) { + if ((opcode & ~0x1FFFF) == GBA_BASE_ROM0) { ++romAddrs; } ARMDecodeARM(opcode, &info); @@ -790,10 +790,10 @@ bool GBAIsMB(struct VFile* vf) { if (vf->seek(vf, pc, SEEK_SET) < 0) { break; } - if ((immediate & ~0x1FFFF) == BASE_WORKING_RAM) { + if ((immediate & ~0x1FFFF) == GBA_BASE_EWRAM) { ++wramLoads; } - if ((immediate & ~0x1FFFF) == BASE_CART0) { + if ((immediate & ~0x1FFFF) == GBA_BASE_ROM0) { ++romLoads; } } @@ -887,9 +887,6 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) { void GBABreakpoint(struct ARMCore* cpu, int immediate) { struct GBA* gba = (struct GBA*) cpu->master; - if (immediate >= CPU_COMPONENT_MAX) { - return; - } switch (immediate) { #ifdef USE_DEBUGGERS case CPU_COMPONENT_DEBUGGER: @@ -900,6 +897,7 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) { .pointId = -1 }; mDebuggerEnter(gba->debugger->d.p, DEBUGGER_ENTER_BREAKPOINT, &info); + return; } break; #endif @@ -918,11 +916,13 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) { if (hook) { ARMRunFake(cpu, hook->patchedOpcode); } + return; } break; default: break; } + ARMRaiseUndefined(cpu); } void GBAFrameStarted(struct GBA* gba) { @@ -983,7 +983,7 @@ void GBATestKeypadIRQ(struct GBA* gba) { uint16_t keysLast = gba->keysLast; uint16_t keysActive = gba->keysActive; - uint16_t keycnt = gba->memory.io[REG_KEYCNT >> 1]; + uint16_t keycnt = gba->memory.io[GBA_REG(KEYCNT)]; if (!(keycnt & 0x4000)) { return; } @@ -1008,11 +1008,11 @@ static void _triggerIRQ(struct mTiming* timing, void* user, uint32_t cyclesLate) UNUSED(cyclesLate); struct GBA* gba = user; gba->cpu->halted = 0; - if (!(gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1])) { + if (!(gba->memory.io[GBA_REG(IE)] & gba->memory.io[GBA_REG(IF)])) { return; } - if (gba->memory.io[REG_IME >> 1] && !gba->cpu->cpsr.i) { + if (gba->memory.io[GBA_REG(IME)] && !gba->cpu->cpsr.i) { ARMRaiseIRQ(gba->cpu); } } diff --git a/src/gba/hle-bios-src.s b/src/gba/hle-bios-src.s index c891479a5..07f827b26 100644 --- a/src/gba/hle-bios-src.s +++ b/src/gba/hle-bios-src.s @@ -123,7 +123,7 @@ subs pc, lr, #4 .word 0 .word 0xE55EC002 -undefBase: +@ Padding for back compat subs pc, lr, #4 .word 0 .word 0x03A0E004 @@ -209,10 +209,10 @@ tst r2, #0x04000000 beq 1f @ Word add r4, r5, r4, lsr #10 -ldmia r12!, {r3} +ldmia r0!, {r3} 2: -cmp r5, r4 -stmltia r5!, {r3} +cmp r1, r4 +stmltia r1!, {r3} blt 2b b 3f @ Halfword @@ -233,9 +233,9 @@ beq 1f @ Word add r4, r5, r4, lsr #10 2: -cmp r5, r4 -ldmltia r12!, {r3} -stmltia r5!, {r3} +cmp r1, r4 +ldmltia r0!, {r3} +stmltia r1!, {r3} blt 2b b 3f @ Halfword @@ -328,3 +328,32 @@ sub lr, #0xC0 bx lr .word 0 .word 0xE129F000 + +.ltorg + +undefBase: +pabtBase: +dabtBase: +fiqBase: +ldr sp, =0x03007FF0 +stmdb sp!, {r12, lr} +mrs r12, spsr +mrs lr, cpsr +stmdb sp!, {r12, lr} +mov lr, #0x08000000 +ldrb r12, [lr, #0x9C] +cmp r12, #0xA5 +bne 1f +ldrb r12, [lr, #0xB4] +tst r12, #0x80 +adr lr, 1f +ldrne pc, =0x09FE2000 +ldreq pc, =0x09FFC000 +1: +ldr sp, =0x03007FF0 +ldr r12, [sp, #-0x10] +msr spsr, r12 +ldmdb sp!, {r12, lr} +subs pc, lr, #4 +.word 0 +.word 0x03A0E004 diff --git a/src/gba/hle-bios.c b/src/gba/hle-bios.c index b68d063a3..841caf543 100644 --- a/src/gba/hle-bios.c +++ b/src/gba/hle-bios.c @@ -2,10 +2,10 @@ #include -const uint8_t hleBios[SIZE_BIOS] = { - 0xd3, 0x00, 0x00, 0xea, 0x66, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea, - 0xfe, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0xa0, 0xe1, - 0x59, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, +const uint8_t hleBios[GBA_SIZE_BIOS] = { + 0xd3, 0x00, 0x00, 0xea, 0xe1, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x00, 0xea, + 0xdf, 0x00, 0x00, 0xea, 0xde, 0x00, 0x00, 0xea, 0x00, 0x00, 0xa0, 0xe1, + 0x59, 0x00, 0x00, 0xea, 0xdb, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xe3, 0x01, 0xd3, 0xa0, 0x03, @@ -50,13 +50,13 @@ const uint8_t hleBios[SIZE_BIOS] = { 0x0c, 0x80, 0xbd, 0xe8, 0x30, 0x40, 0x2d, 0xe9, 0x02, 0x46, 0xa0, 0xe1, 0x00, 0xc0, 0xa0, 0xe1, 0x01, 0x50, 0xa0, 0xe1, 0x01, 0x04, 0x12, 0xe3, 0x0f, 0x00, 0x00, 0x0a, 0x01, 0x03, 0x12, 0xe3, 0x05, 0x00, 0x00, 0x0a, - 0x24, 0x45, 0x85, 0xe0, 0x08, 0x00, 0xbc, 0xe8, 0x04, 0x00, 0x55, 0xe1, - 0x08, 0x00, 0xa5, 0xb8, 0xfc, 0xff, 0xff, 0xba, 0x14, 0x00, 0x00, 0xea, + 0x24, 0x45, 0x85, 0xe0, 0x08, 0x00, 0xb0, 0xe8, 0x04, 0x00, 0x51, 0xe1, + 0x08, 0x00, 0xa1, 0xb8, 0xfc, 0xff, 0xff, 0xba, 0x14, 0x00, 0x00, 0xea, 0x01, 0xc0, 0xcc, 0xe3, 0x01, 0x50, 0xc5, 0xe3, 0xa4, 0x45, 0x85, 0xe0, 0xb0, 0x30, 0xdc, 0xe1, 0x04, 0x00, 0x55, 0xe1, 0xb2, 0x30, 0xc5, 0xb0, 0xfc, 0xff, 0xff, 0xba, 0x0c, 0x00, 0x00, 0xea, 0x01, 0x03, 0x12, 0xe3, - 0x05, 0x00, 0x00, 0x0a, 0x24, 0x45, 0x85, 0xe0, 0x04, 0x00, 0x55, 0xe1, - 0x08, 0x00, 0xbc, 0xb8, 0x08, 0x00, 0xa5, 0xb8, 0xfb, 0xff, 0xff, 0xba, + 0x05, 0x00, 0x00, 0x0a, 0x24, 0x45, 0x85, 0xe0, 0x04, 0x00, 0x51, 0xe1, + 0x08, 0x00, 0xb0, 0xb8, 0x08, 0x00, 0xa1, 0xb8, 0xfb, 0xff, 0xff, 0xba, 0x04, 0x00, 0x00, 0xea, 0xa4, 0x45, 0x85, 0xe0, 0x04, 0x00, 0x55, 0xe1, 0xb2, 0x30, 0xdc, 0xb0, 0xb2, 0x30, 0xc5, 0xb0, 0xfb, 0xff, 0xff, 0xba, 0x17, 0x3e, 0xa0, 0xe3, 0x30, 0x80, 0xbd, 0xe8, 0xf0, 0x47, 0x2d, 0xe9, @@ -78,5 +78,13 @@ const uint8_t hleBios[SIZE_BIOS] = { 0x00, 0x10, 0xa0, 0x13, 0x1e, 0xff, 0x2f, 0x11, 0x1c, 0xe0, 0x9f, 0xe5, 0x00, 0x10, 0x9e, 0xe5, 0x00, 0x00, 0x51, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0x11, 0xc0, 0xe0, 0x4e, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, 0xc0, 0x00, 0x00, 0x02 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x29, 0xe1, 0xc0, 0x00, 0x00, 0x02, + 0x4c, 0xd0, 0x9f, 0xe5, 0x00, 0x50, 0x2d, 0xe9, 0x00, 0xc0, 0x4f, 0xe1, + 0x00, 0xe0, 0x0f, 0xe1, 0x00, 0x50, 0x2d, 0xe9, 0x02, 0xe3, 0xa0, 0xe3, + 0x9c, 0xc0, 0xde, 0xe5, 0xa5, 0x00, 0x5c, 0xe3, 0x04, 0x00, 0x00, 0x1a, + 0xb4, 0xc0, 0xde, 0xe5, 0x80, 0x00, 0x1c, 0xe3, 0x04, 0xe0, 0x8f, 0xe2, + 0x20, 0xf0, 0x9f, 0x15, 0x20, 0xf0, 0x9f, 0x05, 0x14, 0xd0, 0x9f, 0xe5, + 0x10, 0xc0, 0x1d, 0xe5, 0x0c, 0xf0, 0x69, 0xe1, 0x00, 0x50, 0x3d, 0xe9, + 0x04, 0xf0, 0x5e, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe0, 0xa0, 0x03, + 0xf0, 0x7f, 0x00, 0x03, 0x00, 0x20, 0xfe, 0x09, 0x00, 0xc0, 0xff, 0x09 }; diff --git a/src/gba/hle-bios.make b/src/gba/hle-bios.make index b890b43ef..5ac7f1e9b 100644 --- a/src/gba/hle-bios.make +++ b/src/gba/hle-bios.make @@ -15,4 +15,4 @@ hle-bios.c: hle-bios.bin echo >> $@ echo '#include ' >> $@ echo >> $@ - xxd -i $< | sed -e 's/unsigned char hle_bios_bin\[\]/const uint8_t hleBios[SIZE_BIOS]/' -e 's/^ \+/\t/' | grep -v hle_bios_bin_len >> $@ + xxd -i $< | sed -e 's/unsigned char hle_bios_bin\[\]/const uint8_t hleBios[GBA_SIZE_BIOS]/' -e 's/^ \+/\t/' | grep -v hle_bios_bin_len >> $@ diff --git a/src/gba/io.c b/src/gba/io.c index ca0cbe5b5..184146511 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -14,548 +14,496 @@ mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O", "gba.io"); const char* const GBAIORegisterNames[] = { // Video - "DISPCNT", - 0, - "DISPSTAT", - "VCOUNT", - "BG0CNT", - "BG1CNT", - "BG2CNT", - "BG3CNT", - "BG0HOFS", - "BG0VOFS", - "BG1HOFS", - "BG1VOFS", - "BG2HOFS", - "BG2VOFS", - "BG3HOFS", - "BG3VOFS", - "BG2PA", - "BG2PB", - "BG2PC", - "BG2PD", - "BG2X_LO", - "BG2X_HI", - "BG2Y_LO", - "BG2Y_HI", - "BG3PA", - "BG3PB", - "BG3PC", - "BG3PD", - "BG3X_LO", - "BG3X_HI", - "BG3Y_LO", - "BG3Y_HI", - "WIN0H", - "WIN1H", - "WIN0V", - "WIN1V", - "WININ", - "WINOUT", - "MOSAIC", - 0, - "BLDCNT", - "BLDALPHA", - "BLDY", - 0, - 0, - 0, - 0, - 0, + [GBA_REG(DISPCNT)] = "DISPCNT", + [GBA_REG(DISPSTAT)] = "DISPSTAT", + [GBA_REG(VCOUNT)] = "VCOUNT", + [GBA_REG(BG0CNT)] = "BG0CNT", + [GBA_REG(BG1CNT)] = "BG1CNT", + [GBA_REG(BG2CNT)] = "BG2CNT", + [GBA_REG(BG3CNT)] = "BG3CNT", + [GBA_REG(BG0HOFS)] = "BG0HOFS", + [GBA_REG(BG0VOFS)] = "BG0VOFS", + [GBA_REG(BG1HOFS)] = "BG1HOFS", + [GBA_REG(BG1VOFS)] = "BG1VOFS", + [GBA_REG(BG2HOFS)] = "BG2HOFS", + [GBA_REG(BG2VOFS)] = "BG2VOFS", + [GBA_REG(BG3HOFS)] = "BG3HOFS", + [GBA_REG(BG3VOFS)] = "BG3VOFS", + [GBA_REG(BG2PA)] = "BG2PA", + [GBA_REG(BG2PB)] = "BG2PB", + [GBA_REG(BG2PC)] = "BG2PC", + [GBA_REG(BG2PD)] = "BG2PD", + [GBA_REG(BG2X_LO)] = "BG2X_LO", + [GBA_REG(BG2X_HI)] = "BG2X_HI", + [GBA_REG(BG2Y_LO)] = "BG2Y_LO", + [GBA_REG(BG2Y_HI)] = "BG2Y_HI", + [GBA_REG(BG3PA)] = "BG3PA", + [GBA_REG(BG3PB)] = "BG3PB", + [GBA_REG(BG3PC)] = "BG3PC", + [GBA_REG(BG3PD)] = "BG3PD", + [GBA_REG(BG3X_LO)] = "BG3X_LO", + [GBA_REG(BG3X_HI)] = "BG3X_HI", + [GBA_REG(BG3Y_LO)] = "BG3Y_LO", + [GBA_REG(BG3Y_HI)] = "BG3Y_HI", + [GBA_REG(WIN0H)] = "WIN0H", + [GBA_REG(WIN1H)] = "WIN1H", + [GBA_REG(WIN0V)] = "WIN0V", + [GBA_REG(WIN1V)] = "WIN1V", + [GBA_REG(WININ)] = "WININ", + [GBA_REG(WINOUT)] = "WINOUT", + [GBA_REG(MOSAIC)] = "MOSAIC", + [GBA_REG(BLDCNT)] = "BLDCNT", + [GBA_REG(BLDALPHA)] = "BLDALPHA", + [GBA_REG(BLDY)] = "BLDY", // Sound - "SOUND1CNT_LO", - "SOUND1CNT_HI", - "SOUND1CNT_X", - 0, - "SOUND2CNT_LO", - 0, - "SOUND2CNT_HI", - 0, - "SOUND3CNT_LO", - "SOUND3CNT_HI", - "SOUND3CNT_X", - 0, - "SOUND4CNT_LO", - 0, - "SOUND4CNT_HI", - 0, - "SOUNDCNT_LO", - "SOUNDCNT_HI", - "SOUNDCNT_X", - 0, - "SOUNDBIAS", - 0, - 0, - 0, - "WAVE_RAM0_LO", - "WAVE_RAM0_HI", - "WAVE_RAM1_LO", - "WAVE_RAM1_HI", - "WAVE_RAM2_LO", - "WAVE_RAM2_HI", - "WAVE_RAM3_LO", - "WAVE_RAM3_HI", - "FIFO_A_LO", - "FIFO_A_HI", - "FIFO_B_LO", - "FIFO_B_HI", - 0, - 0, - 0, - 0, + [GBA_REG(SOUND1CNT_LO)] = "SOUND1CNT_LO", + [GBA_REG(SOUND1CNT_HI)] = "SOUND1CNT_HI", + [GBA_REG(SOUND1CNT_X)] = "SOUND1CNT_X", + [GBA_REG(SOUND2CNT_LO)] = "SOUND2CNT_LO", + [GBA_REG(SOUND2CNT_HI)] = "SOUND2CNT_HI", + [GBA_REG(SOUND3CNT_LO)] = "SOUND3CNT_LO", + [GBA_REG(SOUND3CNT_HI)] = "SOUND3CNT_HI", + [GBA_REG(SOUND3CNT_X)] = "SOUND3CNT_X", + [GBA_REG(SOUND4CNT_LO)] = "SOUND4CNT_LO", + [GBA_REG(SOUND4CNT_HI)] = "SOUND4CNT_HI", + [GBA_REG(SOUNDCNT_LO)] = "SOUNDCNT_LO", + [GBA_REG(SOUNDCNT_HI)] = "SOUNDCNT_HI", + [GBA_REG(SOUNDCNT_X)] = "SOUNDCNT_X", + [GBA_REG(SOUNDBIAS)] = "SOUNDBIAS", + [GBA_REG(WAVE_RAM0_LO)] = "WAVE_RAM0_LO", + [GBA_REG(WAVE_RAM0_HI)] = "WAVE_RAM0_HI", + [GBA_REG(WAVE_RAM1_LO)] = "WAVE_RAM1_LO", + [GBA_REG(WAVE_RAM1_HI)] = "WAVE_RAM1_HI", + [GBA_REG(WAVE_RAM2_LO)] = "WAVE_RAM2_LO", + [GBA_REG(WAVE_RAM2_HI)] = "WAVE_RAM2_HI", + [GBA_REG(WAVE_RAM3_LO)] = "WAVE_RAM3_LO", + [GBA_REG(WAVE_RAM3_HI)] = "WAVE_RAM3_HI", + [GBA_REG(FIFO_A_LO)] = "FIFO_A_LO", + [GBA_REG(FIFO_A_HI)] = "FIFO_A_HI", + [GBA_REG(FIFO_B_LO)] = "FIFO_B_LO", + [GBA_REG(FIFO_B_HI)] = "FIFO_B_HI", // DMA - "DMA0SAD_LO", - "DMA0SAD_HI", - "DMA0DAD_LO", - "DMA0DAD_HI", - "DMA0CNT_LO", - "DMA0CNT_HI", - "DMA1SAD_LO", - "DMA1SAD_HI", - "DMA1DAD_LO", - "DMA1DAD_HI", - "DMA1CNT_LO", - "DMA1CNT_HI", - "DMA2SAD_LO", - "DMA2SAD_HI", - "DMA2DAD_LO", - "DMA2DAD_HI", - "DMA2CNT_LO", - "DMA2CNT_HI", - "DMA3SAD_LO", - "DMA3SAD_HI", - "DMA3DAD_LO", - "DMA3DAD_HI", - "DMA3CNT_LO", - "DMA3CNT_HI", - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + [GBA_REG(DMA0SAD_LO)] = "DMA0SAD_LO", + [GBA_REG(DMA0SAD_HI)] = "DMA0SAD_HI", + [GBA_REG(DMA0DAD_LO)] = "DMA0DAD_LO", + [GBA_REG(DMA0DAD_HI)] = "DMA0DAD_HI", + [GBA_REG(DMA0CNT_LO)] = "DMA0CNT_LO", + [GBA_REG(DMA0CNT_HI)] = "DMA0CNT_HI", + [GBA_REG(DMA1SAD_LO)] = "DMA1SAD_LO", + [GBA_REG(DMA1SAD_HI)] = "DMA1SAD_HI", + [GBA_REG(DMA1DAD_LO)] = "DMA1DAD_LO", + [GBA_REG(DMA1DAD_HI)] = "DMA1DAD_HI", + [GBA_REG(DMA1CNT_LO)] = "DMA1CNT_LO", + [GBA_REG(DMA1CNT_HI)] = "DMA1CNT_HI", + [GBA_REG(DMA2SAD_LO)] = "DMA2SAD_LO", + [GBA_REG(DMA2SAD_HI)] = "DMA2SAD_HI", + [GBA_REG(DMA2DAD_LO)] = "DMA2DAD_LO", + [GBA_REG(DMA2DAD_HI)] = "DMA2DAD_HI", + [GBA_REG(DMA2CNT_LO)] = "DMA2CNT_LO", + [GBA_REG(DMA2CNT_HI)] = "DMA2CNT_HI", + [GBA_REG(DMA3SAD_LO)] = "DMA3SAD_LO", + [GBA_REG(DMA3SAD_HI)] = "DMA3SAD_HI", + [GBA_REG(DMA3DAD_LO)] = "DMA3DAD_LO", + [GBA_REG(DMA3DAD_HI)] = "DMA3DAD_HI", + [GBA_REG(DMA3CNT_LO)] = "DMA3CNT_LO", + [GBA_REG(DMA3CNT_HI)] = "DMA3CNT_HI", // Timers - "TM0CNT_LO", - "TM0CNT_HI", - "TM1CNT_LO", - "TM1CNT_HI", - "TM2CNT_LO", - "TM2CNT_HI", - "TM3CNT_LO", - "TM3CNT_HI", - - 0, 0, 0, 0, 0, 0, 0, 0, + [GBA_REG(TM0CNT_LO)] = "TM0CNT_LO", + [GBA_REG(TM0CNT_HI)] = "TM0CNT_HI", + [GBA_REG(TM1CNT_LO)] = "TM1CNT_LO", + [GBA_REG(TM1CNT_HI)] = "TM1CNT_HI", + [GBA_REG(TM2CNT_LO)] = "TM2CNT_LO", + [GBA_REG(TM2CNT_HI)] = "TM2CNT_HI", + [GBA_REG(TM3CNT_LO)] = "TM3CNT_LO", + [GBA_REG(TM3CNT_HI)] = "TM3CNT_HI", // SIO - "SIOMULTI0", - "SIOMULTI1", - "SIOMULTI2", - "SIOMULTI3", - "SIOCNT", - "SIOMLT_SEND", - 0, - 0, - "KEYINPUT", - "KEYCNT", - "RCNT", - 0, - 0, - 0, - 0, - 0, - "JOYCNT", - 0, - 0, - 0, - 0, - 0, - 0, - 0, - "JOY_RECV_LO", - "JOY_RECV_HI", - "JOY_TRANS_LO", - "JOY_TRANS_HI", - "JOYSTAT", - 0, - 0, - 0, - - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + [GBA_REG(SIOMULTI0)] = "SIOMULTI0", + [GBA_REG(SIOMULTI1)] = "SIOMULTI1", + [GBA_REG(SIOMULTI2)] = "SIOMULTI2", + [GBA_REG(SIOMULTI3)] = "SIOMULTI3", + [GBA_REG(SIOCNT)] = "SIOCNT", + [GBA_REG(SIOMLT_SEND)] = "SIOMLT_SEND", + [GBA_REG(KEYINPUT)] = "KEYINPUT", + [GBA_REG(KEYCNT)] = "KEYCNT", + [GBA_REG(RCNT)] = "RCNT", + [GBA_REG(JOYCNT)] = "JOYCNT", + [GBA_REG(JOY_RECV_LO)] = "JOY_RECV_LO", + [GBA_REG(JOY_RECV_HI)] = "JOY_RECV_HI", + [GBA_REG(JOY_TRANS_LO)] = "JOY_TRANS_LO", + [GBA_REG(JOY_TRANS_HI)] = "JOY_TRANS_HI", + [GBA_REG(JOYSTAT)] = "JOYSTAT", // Interrupts, etc - "IE", - "IF", - "WAITCNT", - 0, - "IME" + [GBA_REG(IE)] = "IE", + [GBA_REG(IF)] = "IF", + [GBA_REG(WAITCNT)] = "WAITCNT", + [GBA_REG(IME)] = "IME", }; -static const int _isValidRegister[REG_INTERNAL_MAX >> 1] = { - // Video - 1, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 0, 0, - // Audio - 1, 1, 1, 0, 1, 0, 1, 0, - 1, 1, 1, 0, 1, 0, 1, 0, - 1, 1, 1, 0, 1, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, - // DMA - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Timers - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - // SIO - 1, 1, 1, 1, 1, 0, 0, 0, - 1, 1, 1, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Interrupts - 1, 1, 1, 0, 1, 0, 0, 0, +static const int _isValidRegister[GBA_REG(INTERNAL_MAX)] = { + /* 0 2 4 6 8 A C E */ + /* Video */ + /* 00 */ 1, 0, 1, 1, 1, 1, 1, 1, + /* 01 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 02 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 03 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 04 */ 1, 1, 1, 1, 1, 1, 1, 0, + /* 05 */ 1, 1, 1, 0, 0, 0, 0, 0, + /* Audio */ + /* 06 */ 1, 1, 1, 0, 1, 0, 1, 0, + /* 07 */ 1, 1, 1, 0, 1, 0, 1, 0, + /* 08 */ 1, 1, 1, 0, 1, 0, 0, 0, + /* 09 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0A */ 1, 1, 1, 1, 0, 0, 0, 0, + /* DMA */ + /* 0B */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0C */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0D */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0E */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0F */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Timers */ + /* 10 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 11 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* SIO */ + /* 12 */ 1, 1, 1, 1, 1, 0, 0, 0, + /* 13 */ 1, 1, 1, 0, 0, 0, 0, 0, + /* 14 */ 1, 0, 0, 0, 0, 0, 0, 0, + /* 15 */ 1, 1, 1, 1, 1, 0, 0, 0, + /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 17 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 18 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 19 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1A */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1B */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1C */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1D */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1E */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1F */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Interrupts */ + /* 20 */ 1, 1, 1, 0, 1, 0, 0, 0, // Internal registers 1, 1 }; -static const int _isRSpecialRegister[REG_INTERNAL_MAX >> 1] = { - // Video - 0, 0, 1, 1, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - // Audio - 0, 0, 1, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 1, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, - // DMA - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Timers - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - // SIO - 1, 1, 1, 1, 1, 0, 0, 0, - 1, 1, 1, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Interrupts - 0, 0, 0, 0, 0, 0, 0, 0, +static const int _isRSpecialRegister[GBA_REG(INTERNAL_MAX)] = { + /* 0 2 4 6 8 A C E */ + /* Video */ + /* 00 */ 0, 0, 1, 1, 0, 0, 0, 0, + /* 01 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 02 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 03 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 04 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 05 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* Audio */ + /* 06 */ 0, 0, 1, 0, 0, 0, 1, 0, + /* 07 */ 0, 0, 1, 0, 0, 0, 1, 0, + /* 08 */ 0, 0, 0, 0, 1, 0, 0, 0, + /* 09 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0A */ 1, 1, 1, 1, 0, 0, 0, 0, + /* DMA */ + /* 0B */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0C */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0D */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0E */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0F */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Timers */ + /* 10 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 11 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* SIO */ + /* 12 */ 1, 1, 1, 1, 1, 0, 0, 0, + /* 13 */ 1, 1, 1, 0, 0, 0, 0, 0, + /* 14 */ 1, 0, 0, 0, 0, 0, 0, 0, + /* 15 */ 1, 1, 1, 1, 1, 0, 0, 0, + /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 17 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 18 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 19 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1A */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1B */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1C */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1D */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1E */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1F */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Interrupts */ + /* 20 */ 0, 0, 0, 0, 0, 0, 0, 0, // Internal registers 1, 1 }; -static const int _isWSpecialRegister[REG_INTERNAL_MAX >> 1] = { - // Video - 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Audio - 1, 1, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, - 0, 0, 1, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, - // DMA - 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Timers - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - // SIO - 1, 1, 1, 1, 1, 0, 0, 0, - 1, 1, 1, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - // Interrupts - 1, 1, 0, 0, 1, 0, 0, 0, +static const int _isWSpecialRegister[GBA_REG(INTERNAL_MAX)] = { + /* 0 2 4 6 8 A C E */ + /* Video */ + /* 00 */ 0, 0, 1, 1, 0, 0, 0, 0, + /* 01 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 02 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 03 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 04 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 05 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Audio */ + /* 06 */ 0, 0, 1, 0, 0, 0, 1, 0, + /* 07 */ 0, 0, 1, 0, 0, 0, 1, 0, + /* 08 */ 0, 0, 1, 0, 0, 0, 0, 0, + /* 09 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 0A */ 1, 1, 1, 1, 0, 0, 0, 0, + /* DMA */ + /* 0B */ 0, 0, 0, 0, 0, 1, 0, 0, + /* 0C */ 0, 0, 0, 1, 0, 0, 0, 0, + /* 0D */ 0, 1, 0, 0, 0, 0, 0, 1, + /* 0E */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 0F */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Timers */ + /* 10 */ 1, 1, 1, 1, 1, 1, 1, 1, + /* 11 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* SIO */ + /* 12 */ 1, 1, 1, 1, 1, 0, 0, 0, + /* 13 */ 1, 1, 1, 0, 0, 0, 0, 0, + /* 14 */ 1, 0, 0, 0, 0, 0, 0, 0, + /* 15 */ 1, 1, 1, 1, 1, 0, 0, 0, + /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 17 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 18 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 19 */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1A */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1B */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1C */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1D */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1E */ 0, 0, 0, 0, 0, 0, 0, 0, + /* 1F */ 0, 0, 0, 0, 0, 0, 0, 0, + /* Interrupts */ + /* 20 */ 1, 1, 0, 0, 1, 0, 0, 0, // Internal registers 1, 1 }; void GBAIOInit(struct GBA* gba) { - gba->memory.io[REG_DISPCNT >> 1] = 0x0080; - gba->memory.io[REG_RCNT >> 1] = RCNT_INITIAL; - gba->memory.io[REG_KEYINPUT >> 1] = 0x3FF; - gba->memory.io[REG_SOUNDBIAS >> 1] = 0x200; - gba->memory.io[REG_BG2PA >> 1] = 0x100; - gba->memory.io[REG_BG2PD >> 1] = 0x100; - gba->memory.io[REG_BG3PA >> 1] = 0x100; - gba->memory.io[REG_BG3PD >> 1] = 0x100; - gba->memory.io[REG_INTERNAL_EXWAITCNT_LO >> 1] = 0x20; - gba->memory.io[REG_INTERNAL_EXWAITCNT_HI >> 1] = 0xD00; + gba->memory.io[GBA_REG(DISPCNT)] = 0x0080; + gba->memory.io[GBA_REG(RCNT)] = RCNT_INITIAL; + gba->memory.io[GBA_REG(KEYINPUT)] = 0x3FF; + gba->memory.io[GBA_REG(SOUNDBIAS)] = 0x200; + gba->memory.io[GBA_REG(BG2PA)] = 0x100; + gba->memory.io[GBA_REG(BG2PD)] = 0x100; + gba->memory.io[GBA_REG(BG3PA)] = 0x100; + gba->memory.io[GBA_REG(BG3PD)] = 0x100; + gba->memory.io[GBA_REG(INTERNAL_EXWAITCNT_LO)] = 0x20; + gba->memory.io[GBA_REG(INTERNAL_EXWAITCNT_HI)] = 0xD00; if (!gba->biosVf) { - gba->memory.io[REG_VCOUNT >> 1] = 0x7E; - gba->memory.io[REG_POSTFLG >> 1] = 1; + gba->memory.io[GBA_REG(VCOUNT)] = 0x7E; + gba->memory.io[GBA_REG(POSTFLG)] = 1; } } void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { - if (address < REG_SOUND1CNT_LO && (address > REG_VCOUNT || address < REG_DISPSTAT)) { + if (address < GBA_REG_SOUND1CNT_LO && (address > GBA_REG_VCOUNT || address < GBA_REG_DISPSTAT)) { gba->memory.io[address >> 1] = gba->video.renderer->writeVideoRegister(gba->video.renderer, address, value); return; } - if (address >= REG_SOUND1CNT_LO && address <= REG_SOUNDCNT_LO && !gba->audio.enable) { + if (address >= GBA_REG_SOUND1CNT_LO && address <= GBA_REG_SOUNDCNT_LO && !gba->audio.enable) { // Ignore writes to most audio registers if the hardware is off. return; } switch (address) { // Video - case REG_DISPSTAT: + case GBA_REG_DISPSTAT: value &= 0xFFF8; GBAVideoWriteDISPSTAT(&gba->video, value); return; - case REG_VCOUNT: + case GBA_REG_VCOUNT: mLOG(GBA_IO, GAME_ERROR, "Write to read-only I/O register: %03X", address); return; // Audio - case REG_SOUND1CNT_LO: + case GBA_REG_SOUND1CNT_LO: GBAAudioWriteSOUND1CNT_LO(&gba->audio, value); value &= 0x007F; break; - case REG_SOUND1CNT_HI: + case GBA_REG_SOUND1CNT_HI: GBAAudioWriteSOUND1CNT_HI(&gba->audio, value); break; - case REG_SOUND1CNT_X: + case GBA_REG_SOUND1CNT_X: GBAAudioWriteSOUND1CNT_X(&gba->audio, value); value &= 0x47FF; break; - case REG_SOUND2CNT_LO: + case GBA_REG_SOUND2CNT_LO: GBAAudioWriteSOUND2CNT_LO(&gba->audio, value); break; - case REG_SOUND2CNT_HI: + case GBA_REG_SOUND2CNT_HI: GBAAudioWriteSOUND2CNT_HI(&gba->audio, value); value &= 0x47FF; break; - case REG_SOUND3CNT_LO: + case GBA_REG_SOUND3CNT_LO: GBAAudioWriteSOUND3CNT_LO(&gba->audio, value); value &= 0x00E0; break; - case REG_SOUND3CNT_HI: + case GBA_REG_SOUND3CNT_HI: GBAAudioWriteSOUND3CNT_HI(&gba->audio, value); value &= 0xE03F; break; - case REG_SOUND3CNT_X: + case GBA_REG_SOUND3CNT_X: GBAAudioWriteSOUND3CNT_X(&gba->audio, value); // TODO: The low bits need to not be readable, but still 8-bit writable value &= 0x47FF; break; - case REG_SOUND4CNT_LO: + case GBA_REG_SOUND4CNT_LO: GBAAudioWriteSOUND4CNT_LO(&gba->audio, value); value &= 0xFF3F; break; - case REG_SOUND4CNT_HI: + case GBA_REG_SOUND4CNT_HI: GBAAudioWriteSOUND4CNT_HI(&gba->audio, value); value &= 0x40FF; break; - case REG_SOUNDCNT_LO: + case GBA_REG_SOUNDCNT_LO: GBAAudioWriteSOUNDCNT_LO(&gba->audio, value); value &= 0xFF77; break; - case REG_SOUNDCNT_HI: + case GBA_REG_SOUNDCNT_HI: GBAAudioWriteSOUNDCNT_HI(&gba->audio, value); value &= 0x770F; break; - case REG_SOUNDCNT_X: + case GBA_REG_SOUNDCNT_X: GBAAudioWriteSOUNDCNT_X(&gba->audio, value); value &= 0x0080; - value |= gba->memory.io[REG_SOUNDCNT_X >> 1] & 0xF; + value |= gba->memory.io[GBA_REG(SOUNDCNT_X)] & 0xF; break; - case REG_SOUNDBIAS: + case GBA_REG_SOUNDBIAS: value &= 0xC3FE; GBAAudioWriteSOUNDBIAS(&gba->audio, value); break; - case REG_WAVE_RAM0_LO: - case REG_WAVE_RAM1_LO: - case REG_WAVE_RAM2_LO: - case REG_WAVE_RAM3_LO: + case GBA_REG_WAVE_RAM0_LO: + case GBA_REG_WAVE_RAM1_LO: + case GBA_REG_WAVE_RAM2_LO: + case GBA_REG_WAVE_RAM3_LO: GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value); break; - case REG_WAVE_RAM0_HI: - case REG_WAVE_RAM1_HI: - case REG_WAVE_RAM2_HI: - case REG_WAVE_RAM3_HI: + case GBA_REG_WAVE_RAM0_HI: + case GBA_REG_WAVE_RAM1_HI: + case GBA_REG_WAVE_RAM2_HI: + case GBA_REG_WAVE_RAM3_HI: GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16)); break; - case REG_FIFO_A_LO: - case REG_FIFO_B_LO: + case GBA_REG_FIFO_A_LO: + case GBA_REG_FIFO_B_LO: GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value); return; - case REG_FIFO_A_HI: - case REG_FIFO_B_HI: + case GBA_REG_FIFO_A_HI: + case GBA_REG_FIFO_B_HI: GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16)); return; // DMA - case REG_DMA0SAD_LO: - case REG_DMA0DAD_LO: - case REG_DMA1SAD_LO: - case REG_DMA1DAD_LO: - case REG_DMA2SAD_LO: - case REG_DMA2DAD_LO: - case REG_DMA3SAD_LO: - case REG_DMA3DAD_LO: + case GBA_REG_DMA0SAD_LO: + case GBA_REG_DMA0DAD_LO: + case GBA_REG_DMA1SAD_LO: + case GBA_REG_DMA1DAD_LO: + case GBA_REG_DMA2SAD_LO: + case GBA_REG_DMA2DAD_LO: + case GBA_REG_DMA3SAD_LO: + case GBA_REG_DMA3DAD_LO: GBAIOWrite32(gba, address, (gba->memory.io[(address >> 1) + 1] << 16) | value); break; - case REG_DMA0SAD_HI: - case REG_DMA0DAD_HI: - case REG_DMA1SAD_HI: - case REG_DMA1DAD_HI: - case REG_DMA2SAD_HI: - case REG_DMA2DAD_HI: - case REG_DMA3SAD_HI: - case REG_DMA3DAD_HI: + case GBA_REG_DMA0SAD_HI: + case GBA_REG_DMA0DAD_HI: + case GBA_REG_DMA1SAD_HI: + case GBA_REG_DMA1DAD_HI: + case GBA_REG_DMA2SAD_HI: + case GBA_REG_DMA2DAD_HI: + case GBA_REG_DMA3SAD_HI: + case GBA_REG_DMA3DAD_HI: GBAIOWrite32(gba, address - 2, gba->memory.io[(address >> 1) - 1] | (value << 16)); break; - case REG_DMA0CNT_LO: + case GBA_REG_DMA0CNT_LO: GBADMAWriteCNT_LO(gba, 0, value & 0x3FFF); break; - case REG_DMA0CNT_HI: + case GBA_REG_DMA0CNT_HI: value = GBADMAWriteCNT_HI(gba, 0, value); break; - case REG_DMA1CNT_LO: + case GBA_REG_DMA1CNT_LO: GBADMAWriteCNT_LO(gba, 1, value & 0x3FFF); break; - case REG_DMA1CNT_HI: + case GBA_REG_DMA1CNT_HI: value = GBADMAWriteCNT_HI(gba, 1, value); break; - case REG_DMA2CNT_LO: + case GBA_REG_DMA2CNT_LO: GBADMAWriteCNT_LO(gba, 2, value & 0x3FFF); break; - case REG_DMA2CNT_HI: + case GBA_REG_DMA2CNT_HI: value = GBADMAWriteCNT_HI(gba, 2, value); break; - case REG_DMA3CNT_LO: + case GBA_REG_DMA3CNT_LO: GBADMAWriteCNT_LO(gba, 3, value); break; - case REG_DMA3CNT_HI: + case GBA_REG_DMA3CNT_HI: value = GBADMAWriteCNT_HI(gba, 3, value); break; // Timers - case REG_TM0CNT_LO: + case GBA_REG_TM0CNT_LO: GBATimerWriteTMCNT_LO(gba, 0, value); return; - case REG_TM1CNT_LO: + case GBA_REG_TM1CNT_LO: GBATimerWriteTMCNT_LO(gba, 1, value); return; - case REG_TM2CNT_LO: + case GBA_REG_TM2CNT_LO: GBATimerWriteTMCNT_LO(gba, 2, value); return; - case REG_TM3CNT_LO: + case GBA_REG_TM3CNT_LO: GBATimerWriteTMCNT_LO(gba, 3, value); return; - case REG_TM0CNT_HI: + case GBA_REG_TM0CNT_HI: value &= 0x00C7; GBATimerWriteTMCNT_HI(gba, 0, value); break; - case REG_TM1CNT_HI: + case GBA_REG_TM1CNT_HI: value &= 0x00C7; GBATimerWriteTMCNT_HI(gba, 1, value); break; - case REG_TM2CNT_HI: + case GBA_REG_TM2CNT_HI: value &= 0x00C7; GBATimerWriteTMCNT_HI(gba, 2, value); break; - case REG_TM3CNT_HI: + case GBA_REG_TM3CNT_HI: value &= 0x00C7; GBATimerWriteTMCNT_HI(gba, 3, value); break; // SIO - case REG_SIOCNT: + case GBA_REG_SIOCNT: GBASIOWriteSIOCNT(&gba->sio, value); break; - case REG_RCNT: + case GBA_REG_RCNT: value &= 0xC1FF; GBASIOWriteRCNT(&gba->sio, value); break; - case REG_JOY_TRANS_LO: - case REG_JOY_TRANS_HI: - gba->memory.io[REG_JOYSTAT >> 1] |= JOYSTAT_TRANS; + case GBA_REG_JOY_TRANS_LO: + case GBA_REG_JOY_TRANS_HI: + gba->memory.io[GBA_REG(JOYSTAT)] |= JOYSTAT_TRANS; // Fall through - case REG_SIODATA32_LO: - case REG_SIODATA32_HI: - case REG_SIOMLT_SEND: - case REG_JOYCNT: - case REG_JOYSTAT: - case REG_JOY_RECV_LO: - case REG_JOY_RECV_HI: + case GBA_REG_SIODATA32_LO: + case GBA_REG_SIODATA32_HI: + case GBA_REG_SIOMLT_SEND: + case GBA_REG_JOYCNT: + case GBA_REG_JOYSTAT: + case GBA_REG_JOY_RECV_LO: + case GBA_REG_JOY_RECV_HI: value = GBASIOWriteRegister(&gba->sio, address, value); break; // Interrupts and misc - case REG_KEYCNT: + case GBA_REG_KEYCNT: value &= 0xC3FF; if (gba->keysLast < 0x400) { gba->keysLast &= gba->memory.io[address >> 1] | ~value; @@ -563,36 +511,51 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { gba->memory.io[address >> 1] = value; GBATestKeypadIRQ(gba); return; - case REG_WAITCNT: + case GBA_REG_WAITCNT: value &= 0x5FFF; GBAAdjustWaitstates(gba, value); break; - case REG_IE: - gba->memory.io[REG_IE >> 1] = value; + case GBA_REG_IE: + gba->memory.io[GBA_REG(IE)] = value; GBATestIRQ(gba, 1); return; - case REG_IF: - value = gba->memory.io[REG_IF >> 1] & ~value; - gba->memory.io[REG_IF >> 1] = value; + case GBA_REG_IF: + value = gba->memory.io[GBA_REG(IF)] & ~value; + gba->memory.io[GBA_REG(IF)] = value; GBATestIRQ(gba, 1); return; - case REG_IME: - gba->memory.io[REG_IME >> 1] = value & 1; + case GBA_REG_IME: + gba->memory.io[GBA_REG(IME)] = value & 1; GBATestIRQ(gba, 1); return; - case REG_MAX: + case GBA_REG_MAX: // Some bad interrupt libraries will write to this break; - case REG_EXWAITCNT_HI: + case GBA_REG_POSTFLG: + if (gba->memory.activeRegion == GBA_REGION_BIOS) { + if (gba->memory.io[address >> 1]) { + if (value & 0x8000) { + GBAStop(gba); + } else { + GBAHalt(gba); + } + } + value &= ~0x8000; + } else { + mLOG(GBA_IO, GAME_ERROR, "Write to BIOS-only I/O register: %03X", address); + return; + } + break; + case GBA_REG_EXWAITCNT_HI: // This register sits outside of the normal I/O block, so we need to stash it somewhere unused - address = REG_INTERNAL_EXWAITCNT_HI; + address = GBA_REG_INTERNAL_EXWAITCNT_HI; value &= 0xFF00; GBAAdjustEWRAMWaitstates(gba, value); break; - case REG_DEBUG_ENABLE: + case GBA_REG_DEBUG_ENABLE: gba->debug = value == 0xC0DE; return; - case REG_DEBUG_FLAGS: + case GBA_REG_DEBUG_FLAGS: if (gba->debug) { GBADebug(gba, value); @@ -600,12 +563,12 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { } // Fall through default: - if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { - STORE_16LE(value, address - REG_DEBUG_STRING, gba->debugString); + if (address >= GBA_REG_DEBUG_STRING && address - GBA_REG_DEBUG_STRING < sizeof(gba->debugString)) { + STORE_16LE(value, address - GBA_REG_DEBUG_STRING, gba->debugString); return; } mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address); - if (address >= REG_MAX) { + if (address >= GBA_REG_MAX) { mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address); return; } @@ -615,28 +578,15 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { } void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { - if (address == REG_HALTCNT) { - value &= 0x80; - if (!value) { - GBAHalt(gba); - } else { - GBAStop(gba); - } + if (address >= GBA_REG_DEBUG_STRING && address - GBA_REG_DEBUG_STRING < sizeof(gba->debugString)) { + gba->debugString[address - GBA_REG_DEBUG_STRING] = value; return; } - if (address == REG_POSTFLG) { - gba->memory.io[(address & (SIZE_IO - 1)) >> 1] = value; - return; - } - if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { - gba->debugString[address - REG_DEBUG_STRING] = value; - return; - } - if (address > SIZE_IO) { + if (address > GBA_SIZE_IO) { return; } uint16_t value16 = value << (8 * (address & 1)); - value16 |= (gba->memory.io[(address & (SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1))); + value16 |= (gba->memory.io[(address & (GBA_SIZE_IO - 1)) >> 1]) & ~(0xFF << (8 * (address & 1))); GBAIOWrite(gba, address & 0xFFFFFFFE, value16); } @@ -645,49 +595,49 @@ void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { // Wave RAM can be written and read even if the audio hardware is disabled. // However, it is not possible to switch between the two banks because it // isn't possible to write to register SOUND3CNT_LO. - case REG_WAVE_RAM0_LO: + case GBA_REG_WAVE_RAM0_LO: GBAAudioWriteWaveRAM(&gba->audio, 0, value); break; - case REG_WAVE_RAM1_LO: + case GBA_REG_WAVE_RAM1_LO: GBAAudioWriteWaveRAM(&gba->audio, 1, value); break; - case REG_WAVE_RAM2_LO: + case GBA_REG_WAVE_RAM2_LO: GBAAudioWriteWaveRAM(&gba->audio, 2, value); break; - case REG_WAVE_RAM3_LO: + case GBA_REG_WAVE_RAM3_LO: GBAAudioWriteWaveRAM(&gba->audio, 3, value); break; - case REG_FIFO_A_LO: - case REG_FIFO_B_LO: + case GBA_REG_FIFO_A_LO: + case GBA_REG_FIFO_B_LO: value = GBAAudioWriteFIFO(&gba->audio, address, value); break; - case REG_DMA0SAD_LO: + case GBA_REG_DMA0SAD_LO: value = GBADMAWriteSAD(gba, 0, value); break; - case REG_DMA0DAD_LO: + case GBA_REG_DMA0DAD_LO: value = GBADMAWriteDAD(gba, 0, value); break; - case REG_DMA1SAD_LO: + case GBA_REG_DMA1SAD_LO: value = GBADMAWriteSAD(gba, 1, value); break; - case REG_DMA1DAD_LO: + case GBA_REG_DMA1DAD_LO: value = GBADMAWriteDAD(gba, 1, value); break; - case REG_DMA2SAD_LO: + case GBA_REG_DMA2SAD_LO: value = GBADMAWriteSAD(gba, 2, value); break; - case REG_DMA2DAD_LO: + case GBA_REG_DMA2DAD_LO: value = GBADMAWriteDAD(gba, 2, value); break; - case REG_DMA3SAD_LO: + case GBA_REG_DMA3SAD_LO: value = GBADMAWriteSAD(gba, 3, value); break; - case REG_DMA3DAD_LO: + case GBA_REG_DMA3DAD_LO: value = GBADMAWriteDAD(gba, 3, value); break; default: - if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { - STORE_32LE(value, address - REG_DEBUG_STRING, gba->debugString); + if (address >= GBA_REG_DEBUG_STRING && address - GBA_REG_DEBUG_STRING < sizeof(gba->debugString)) { + STORE_32LE(value, address - GBA_REG_DEBUG_STRING, gba->debugString); return; } GBAIOWrite(gba, address, value & 0xFFFF); @@ -702,33 +652,33 @@ bool GBAIOIsReadConstant(uint32_t address) { switch (address) { default: return false; - case REG_BG0CNT: - case REG_BG1CNT: - case REG_BG2CNT: - case REG_BG3CNT: - case REG_WININ: - case REG_WINOUT: - case REG_BLDCNT: - case REG_BLDALPHA: - case REG_SOUND1CNT_LO: - case REG_SOUND1CNT_HI: - case REG_SOUND1CNT_X: - case REG_SOUND2CNT_LO: - case REG_SOUND2CNT_HI: - case REG_SOUND3CNT_LO: - case REG_SOUND3CNT_HI: - case REG_SOUND3CNT_X: - case REG_SOUND4CNT_LO: - case REG_SOUND4CNT_HI: - case REG_SOUNDCNT_LO: - case REG_SOUNDCNT_HI: - case REG_TM0CNT_HI: - case REG_TM1CNT_HI: - case REG_TM2CNT_HI: - case REG_TM3CNT_HI: - case REG_KEYINPUT: - case REG_KEYCNT: - case REG_IE: + case GBA_REG_BG0CNT: + case GBA_REG_BG1CNT: + case GBA_REG_BG2CNT: + case GBA_REG_BG3CNT: + case GBA_REG_WININ: + case GBA_REG_WINOUT: + case GBA_REG_BLDCNT: + case GBA_REG_BLDALPHA: + case GBA_REG_SOUND1CNT_LO: + case GBA_REG_SOUND1CNT_HI: + case GBA_REG_SOUND1CNT_X: + case GBA_REG_SOUND2CNT_LO: + case GBA_REG_SOUND2CNT_HI: + case GBA_REG_SOUND3CNT_LO: + case GBA_REG_SOUND3CNT_HI: + case GBA_REG_SOUND3CNT_X: + case GBA_REG_SOUND4CNT_LO: + case GBA_REG_SOUND4CNT_HI: + case GBA_REG_SOUNDCNT_LO: + case GBA_REG_SOUNDCNT_HI: + case GBA_REG_TM0CNT_HI: + case GBA_REG_TM1CNT_HI: + case GBA_REG_TM2CNT_HI: + case GBA_REG_TM3CNT_HI: + case GBA_REG_KEYINPUT: + case GBA_REG_KEYCNT: + case GBA_REG_IE: return true; } } @@ -741,20 +691,20 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { switch (address) { // Reading this takes two cycles (1N+1I), so let's remove them preemptively - case REG_TM0CNT_LO: + case GBA_REG_TM0CNT_LO: GBATimerUpdateRegister(gba, 0, 2); break; - case REG_TM1CNT_LO: + case GBA_REG_TM1CNT_LO: GBATimerUpdateRegister(gba, 1, 2); break; - case REG_TM2CNT_LO: + case GBA_REG_TM2CNT_LO: GBATimerUpdateRegister(gba, 2, 2); break; - case REG_TM3CNT_LO: + case GBA_REG_TM3CNT_LO: GBATimerUpdateRegister(gba, 3, 2); break; - case REG_KEYINPUT: { + case GBA_REG_KEYINPUT: { size_t c; for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); @@ -784,157 +734,154 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { gba->memory.io[address >> 1] = 0x3FF ^ input; } break; - case REG_SIOCNT: + case GBA_REG_SIOCNT: return gba->sio.siocnt; - case REG_RCNT: + case GBA_REG_RCNT: return gba->sio.rcnt; - case REG_BG0HOFS: - case REG_BG0VOFS: - case REG_BG1HOFS: - case REG_BG1VOFS: - case REG_BG2HOFS: - case REG_BG2VOFS: - case REG_BG3HOFS: - case REG_BG3VOFS: - case REG_BG2PA: - case REG_BG2PB: - case REG_BG2PC: - case REG_BG2PD: - case REG_BG2X_LO: - case REG_BG2X_HI: - case REG_BG2Y_LO: - case REG_BG2Y_HI: - case REG_BG3PA: - case REG_BG3PB: - case REG_BG3PC: - case REG_BG3PD: - case REG_BG3X_LO: - case REG_BG3X_HI: - case REG_BG3Y_LO: - case REG_BG3Y_HI: - case REG_WIN0H: - case REG_WIN1H: - case REG_WIN0V: - case REG_WIN1V: - case REG_MOSAIC: - case REG_BLDY: - case REG_FIFO_A_LO: - case REG_FIFO_A_HI: - case REG_FIFO_B_LO: - case REG_FIFO_B_HI: - case REG_DMA0SAD_LO: - case REG_DMA0SAD_HI: - case REG_DMA0DAD_LO: - case REG_DMA0DAD_HI: - case REG_DMA1SAD_LO: - case REG_DMA1SAD_HI: - case REG_DMA1DAD_LO: - case REG_DMA1DAD_HI: - case REG_DMA2SAD_LO: - case REG_DMA2SAD_HI: - case REG_DMA2DAD_LO: - case REG_DMA2DAD_HI: - case REG_DMA3SAD_LO: - case REG_DMA3SAD_HI: - case REG_DMA3DAD_LO: - case REG_DMA3DAD_HI: + case GBA_REG_BG0HOFS: + case GBA_REG_BG0VOFS: + case GBA_REG_BG1HOFS: + case GBA_REG_BG1VOFS: + case GBA_REG_BG2HOFS: + case GBA_REG_BG2VOFS: + case GBA_REG_BG3HOFS: + case GBA_REG_BG3VOFS: + case GBA_REG_BG2PA: + case GBA_REG_BG2PB: + case GBA_REG_BG2PC: + case GBA_REG_BG2PD: + case GBA_REG_BG2X_LO: + case GBA_REG_BG2X_HI: + case GBA_REG_BG2Y_LO: + case GBA_REG_BG2Y_HI: + case GBA_REG_BG3PA: + case GBA_REG_BG3PB: + case GBA_REG_BG3PC: + case GBA_REG_BG3PD: + case GBA_REG_BG3X_LO: + case GBA_REG_BG3X_HI: + case GBA_REG_BG3Y_LO: + case GBA_REG_BG3Y_HI: + case GBA_REG_WIN0H: + case GBA_REG_WIN1H: + case GBA_REG_WIN0V: + case GBA_REG_WIN1V: + case GBA_REG_MOSAIC: + case GBA_REG_BLDY: + case GBA_REG_FIFO_A_LO: + case GBA_REG_FIFO_A_HI: + case GBA_REG_FIFO_B_LO: + case GBA_REG_FIFO_B_HI: + case GBA_REG_DMA0SAD_LO: + case GBA_REG_DMA0SAD_HI: + case GBA_REG_DMA0DAD_LO: + case GBA_REG_DMA0DAD_HI: + case GBA_REG_DMA1SAD_LO: + case GBA_REG_DMA1SAD_HI: + case GBA_REG_DMA1DAD_LO: + case GBA_REG_DMA1DAD_HI: + case GBA_REG_DMA2SAD_LO: + case GBA_REG_DMA2SAD_HI: + case GBA_REG_DMA2DAD_LO: + case GBA_REG_DMA2DAD_HI: + case GBA_REG_DMA3SAD_LO: + case GBA_REG_DMA3SAD_HI: + case GBA_REG_DMA3DAD_LO: + case GBA_REG_DMA3DAD_HI: // Write-only register mLOG(GBA_IO, GAME_ERROR, "Read from write-only I/O register: %03X", address); return GBALoadBad(gba->cpu); - case REG_DMA0CNT_LO: - case REG_DMA1CNT_LO: - case REG_DMA2CNT_LO: - case REG_DMA3CNT_LO: + case GBA_REG_DMA0CNT_LO: + case GBA_REG_DMA1CNT_LO: + case GBA_REG_DMA2CNT_LO: + case GBA_REG_DMA3CNT_LO: // Many, many things read from the DMA register - case REG_MAX: + case GBA_REG_MAX: // Some bad interrupt libraries will read from this // (Silent) write-only register return 0; - case REG_JOY_RECV_LO: - case REG_JOY_RECV_HI: - gba->memory.io[REG_JOYSTAT >> 1] &= ~JOYSTAT_RECV; - break; - - case REG_POSTFLG: - mLOG(GBA_IO, STUB, "Stub I/O register read: %03x", address); + case GBA_REG_JOY_RECV_LO: + case GBA_REG_JOY_RECV_HI: + gba->memory.io[GBA_REG(JOYSTAT)] &= ~JOYSTAT_RECV; break; // Wave RAM can be written and read even if the audio hardware is disabled. // However, it is not possible to switch between the two banks because it // isn't possible to write to register SOUND3CNT_LO. - case REG_WAVE_RAM0_LO: + case GBA_REG_WAVE_RAM0_LO: return GBAAudioReadWaveRAM(&gba->audio, 0) & 0xFFFF; - case REG_WAVE_RAM0_HI: + case GBA_REG_WAVE_RAM0_HI: return GBAAudioReadWaveRAM(&gba->audio, 0) >> 16; - case REG_WAVE_RAM1_LO: + case GBA_REG_WAVE_RAM1_LO: return GBAAudioReadWaveRAM(&gba->audio, 1) & 0xFFFF; - case REG_WAVE_RAM1_HI: + case GBA_REG_WAVE_RAM1_HI: return GBAAudioReadWaveRAM(&gba->audio, 1) >> 16; - case REG_WAVE_RAM2_LO: + case GBA_REG_WAVE_RAM2_LO: return GBAAudioReadWaveRAM(&gba->audio, 2) & 0xFFFF; - case REG_WAVE_RAM2_HI: + case GBA_REG_WAVE_RAM2_HI: return GBAAudioReadWaveRAM(&gba->audio, 2) >> 16; - case REG_WAVE_RAM3_LO: + case GBA_REG_WAVE_RAM3_LO: return GBAAudioReadWaveRAM(&gba->audio, 3) & 0xFFFF; - case REG_WAVE_RAM3_HI: + case GBA_REG_WAVE_RAM3_HI: return GBAAudioReadWaveRAM(&gba->audio, 3) >> 16; - case REG_SOUND1CNT_LO: - case REG_SOUND1CNT_HI: - case REG_SOUND1CNT_X: - case REG_SOUND2CNT_LO: - case REG_SOUND2CNT_HI: - case REG_SOUND3CNT_LO: - case REG_SOUND3CNT_HI: - case REG_SOUND3CNT_X: - case REG_SOUND4CNT_LO: - case REG_SOUND4CNT_HI: - case REG_SOUNDCNT_LO: - if (!GBAudioEnableIsEnable(gba->memory.io[REG_SOUNDCNT_X >> 1])) { + case GBA_REG_SOUND1CNT_LO: + case GBA_REG_SOUND1CNT_HI: + case GBA_REG_SOUND1CNT_X: + case GBA_REG_SOUND2CNT_LO: + case GBA_REG_SOUND2CNT_HI: + case GBA_REG_SOUND3CNT_LO: + case GBA_REG_SOUND3CNT_HI: + case GBA_REG_SOUND3CNT_X: + case GBA_REG_SOUND4CNT_LO: + case GBA_REG_SOUND4CNT_HI: + case GBA_REG_SOUNDCNT_LO: + if (!GBAudioEnableIsEnable(gba->memory.io[GBA_REG(SOUNDCNT_X)])) { // TODO: Is writing allowed when the circuit is disabled? return 0; } // Fall through - case REG_DISPCNT: - case REG_GREENSWP: - case REG_DISPSTAT: - case REG_VCOUNT: - case REG_BG0CNT: - case REG_BG1CNT: - case REG_BG2CNT: - case REG_BG3CNT: - case REG_WININ: - case REG_WINOUT: - case REG_BLDCNT: - case REG_BLDALPHA: - case REG_SOUNDCNT_HI: - case REG_SOUNDCNT_X: - case REG_SOUNDBIAS: - case REG_DMA0CNT_HI: - case REG_DMA1CNT_HI: - case REG_DMA2CNT_HI: - case REG_DMA3CNT_HI: - case REG_TM0CNT_HI: - case REG_TM1CNT_HI: - case REG_TM2CNT_HI: - case REG_TM3CNT_HI: - case REG_KEYCNT: - case REG_SIOMULTI0: - case REG_SIOMULTI1: - case REG_SIOMULTI2: - case REG_SIOMULTI3: - case REG_SIOMLT_SEND: - case REG_JOYCNT: - case REG_JOY_TRANS_LO: - case REG_JOY_TRANS_HI: - case REG_JOYSTAT: - case REG_IE: - case REG_IF: - case REG_WAITCNT: - case REG_IME: + case GBA_REG_DISPCNT: + case GBA_REG_GREENSWP: + case GBA_REG_DISPSTAT: + case GBA_REG_VCOUNT: + case GBA_REG_BG0CNT: + case GBA_REG_BG1CNT: + case GBA_REG_BG2CNT: + case GBA_REG_BG3CNT: + case GBA_REG_WININ: + case GBA_REG_WINOUT: + case GBA_REG_BLDCNT: + case GBA_REG_BLDALPHA: + case GBA_REG_SOUNDCNT_HI: + case GBA_REG_SOUNDCNT_X: + case GBA_REG_SOUNDBIAS: + case GBA_REG_DMA0CNT_HI: + case GBA_REG_DMA1CNT_HI: + case GBA_REG_DMA2CNT_HI: + case GBA_REG_DMA3CNT_HI: + case GBA_REG_TM0CNT_HI: + case GBA_REG_TM1CNT_HI: + case GBA_REG_TM2CNT_HI: + case GBA_REG_TM3CNT_HI: + case GBA_REG_KEYCNT: + case GBA_REG_SIOMULTI0: + case GBA_REG_SIOMULTI1: + case GBA_REG_SIOMULTI2: + case GBA_REG_SIOMULTI3: + case GBA_REG_SIOMLT_SEND: + case GBA_REG_JOYCNT: + case GBA_REG_JOY_TRANS_LO: + case GBA_REG_JOY_TRANS_HI: + case GBA_REG_JOYSTAT: + case GBA_REG_IE: + case GBA_REG_IF: + case GBA_REG_WAITCNT: + case GBA_REG_IME: + case GBA_REG_POSTFLG: // Handled transparently by registers break; case 0x066: @@ -949,14 +896,15 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case 0x142: case 0x15A: case 0x206: + case 0x302: mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return 0; // These registers sit outside of the normal I/O block, so we need to stash them somewhere unused - case REG_EXWAITCNT_LO: - case REG_EXWAITCNT_HI: - address += REG_INTERNAL_EXWAITCNT_LO - REG_EXWAITCNT_LO; + case GBA_REG_EXWAITCNT_LO: + case GBA_REG_EXWAITCNT_HI: + address += GBA_REG_INTERNAL_EXWAITCNT_LO - GBA_REG_EXWAITCNT_LO; break; - case REG_DEBUG_ENABLE: + case GBA_REG_DEBUG_ENABLE: if (gba->debug) { return 0x1DEA; } @@ -970,7 +918,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { int i; - for (i = 0; i < REG_INTERNAL_MAX; i += 2) { + for (i = 0; i < GBA_REG_INTERNAL_MAX; i += 2) { if (_isRSpecialRegister[i >> 1]) { STORE_16(gba->memory.io[i >> 1], i, state->io); } else if (_isValidRegister[i >> 1]) { @@ -980,7 +928,7 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { } for (i = 0; i < 4; ++i) { - STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io); + STORE_16(gba->memory.io[(GBA_REG_DMA0CNT_LO + i * 12) >> 1], (GBA_REG_DMA0CNT_LO + i * 12), state->io); STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload); STORE_32(gba->timers[i].lastEvent - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].lastEvent); STORE_32(gba->timers[i].event.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextEvent); @@ -998,11 +946,11 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { } void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { - LOAD_16(gba->memory.io[REG_SOUNDCNT_X >> 1], REG_SOUNDCNT_X, state->io); - GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]); + LOAD_16(gba->memory.io[GBA_REG(SOUNDCNT_X)], GBA_REG_SOUNDCNT_X, state->io); + GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[GBA_REG(SOUNDCNT_X)]); int i; - for (i = 0; i < REG_MAX; i += 2) { + for (i = 0; i < GBA_REG_MAX; i += 2) { if (_isWSpecialRegister[i >> 1]) { LOAD_16(gba->memory.io[i >> 1], i, state->io); } else if (_isValidRegister[i >> 1]) { @@ -1012,7 +960,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { } } if (state->versionMagic >= 0x01000006) { - GBAIOWrite(gba, REG_EXWAITCNT_HI, gba->memory.io[REG_INTERNAL_EXWAITCNT_HI >> 1]); + GBAIOWrite(gba, GBA_REG_EXWAITCNT_HI, gba->memory.io[GBA_REG(INTERNAL_EXWAITCNT_HI)]); } uint32_t when; @@ -1028,14 +976,14 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { gba->timers[i].event.when = when + mTimingCurrentTime(&gba->timing); } - LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io); + LOAD_16(gba->memory.dma[i].reg, (GBA_REG_DMA0CNT_HI + i * 12), state->io); LOAD_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when); } - gba->sio.siocnt = gba->memory.io[REG_SIOCNT >> 1]; - GBASIOWriteRCNT(&gba->sio, gba->memory.io[REG_RCNT >> 1]); + gba->sio.siocnt = gba->memory.io[GBA_REG(SIOCNT)]; + GBASIOWriteRCNT(&gba->sio, gba->memory.io[GBA_REG(RCNT)]); LOAD_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister); LOAD_32(gba->dmaPC, 0, &state->dmaBlockPC); diff --git a/src/gba/memory.c b/src/gba/memory.c index c9a1f59dd..9418a2706 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -89,8 +89,8 @@ void GBAMemoryInit(struct GBA* gba) { gba->memory.agbPrintBuffer = NULL; gba->memory.agbPrintBufferBackup = NULL; - gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM + SIZE_WORKING_IRAM); - gba->memory.iwram = &gba->memory.wram[SIZE_WORKING_RAM >> 2]; + gba->memory.wram = anonymousMemoryMap(GBA_SIZE_EWRAM + GBA_SIZE_IWRAM); + gba->memory.iwram = &gba->memory.wram[GBA_SIZE_EWRAM >> 2]; GBADMAInit(gba); GBAVFameInit(&gba->memory.vfame); @@ -101,15 +101,15 @@ void GBAMemoryInit(struct GBA* gba) { } void GBAMemoryDeinit(struct GBA* gba) { - mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM + SIZE_WORKING_IRAM); + mappedMemoryFree(gba->memory.wram, GBA_SIZE_EWRAM + GBA_SIZE_IWRAM); if (gba->memory.rom) { mappedMemoryFree(gba->memory.rom, gba->memory.romSize); } if (gba->memory.agbPrintBuffer) { - mappedMemoryFree(gba->memory.agbPrintBuffer, SIZE_AGB_PRINT); + mappedMemoryFree(gba->memory.agbPrintBuffer, GBA_SIZE_AGB_PRINT); } if (gba->memory.agbPrintBufferBackup) { - mappedMemoryFree(gba->memory.agbPrintBufferBackup, SIZE_AGB_PRINT); + mappedMemoryFree(gba->memory.agbPrintBufferBackup, GBA_SIZE_AGB_PRINT); } GBACartEReaderDeinit(&gba->memory.ereader); @@ -117,29 +117,18 @@ void GBAMemoryDeinit(struct GBA* gba) { void GBAMemoryReset(struct GBA* gba) { if (gba->memory.wram && gba->memory.rom) { - memset(gba->memory.wram, 0, SIZE_WORKING_RAM); + memset(gba->memory.wram, 0, GBA_SIZE_EWRAM); } if (gba->memory.iwram) { - memset(gba->memory.iwram, 0, SIZE_WORKING_IRAM); + memset(gba->memory.iwram, 0, GBA_SIZE_IWRAM); } memset(gba->memory.io, 0, sizeof(gba->memory.io)); GBAAdjustWaitstates(gba, 0); GBAAdjustEWRAMWaitstates(gba, 0x0D00); - gba->memory.activeRegion = -1; - gba->memory.agbPrintProtect = 0; - gba->memory.agbPrintBase = 0; - memset(&gba->memory.agbPrintCtx, 0, sizeof(gba->memory.agbPrintCtx)); - if (gba->memory.agbPrintBuffer) { - mappedMemoryFree(gba->memory.agbPrintBuffer, SIZE_AGB_PRINT); - gba->memory.agbPrintBuffer = NULL; - } - if (gba->memory.agbPrintBufferBackup) { - mappedMemoryFree(gba->memory.agbPrintBufferBackup, SIZE_AGB_PRINT); - gba->memory.agbPrintBufferBackup = NULL; - } + GBAMemoryClearAGBPrint(gba); gba->memory.prefetch = false; gba->memory.lastPrefetchedPc = 0; @@ -153,6 +142,21 @@ void GBAMemoryReset(struct GBA* gba) { memset(&gba->memory.matrix, 0, sizeof(gba->memory.matrix)); } +void GBAMemoryClearAGBPrint(struct GBA* gba) { + gba->memory.activeRegion = -1; + gba->memory.agbPrintProtect = 0; + gba->memory.agbPrintBase = 0; + memset(&gba->memory.agbPrintCtx, 0, sizeof(gba->memory.agbPrintCtx)); + if (gba->memory.agbPrintBuffer) { + mappedMemoryFree(gba->memory.agbPrintBuffer, GBA_SIZE_AGB_PRINT); + gba->memory.agbPrintBuffer = NULL; + } + if (gba->memory.agbPrintBufferBackup) { + mappedMemoryFree(gba->memory.agbPrintBufferBackup, GBA_SIZE_AGB_PRINT); + gba->memory.agbPrintBufferBackup = NULL; + } +} + static void _analyzeForIdleLoop(struct GBA* gba, struct ARMCore* cpu, uint32_t address) { struct ARMInstructionInfo info; uint32_t nextAddress = address; @@ -186,11 +190,11 @@ static void _analyzeForIdleLoop(struct GBA* gba, struct ARMCore* cpu, uint32_t a } else { loadAddress += offset; } - if ((loadAddress >> BASE_OFFSET) == REGION_IO && !GBAIOIsReadConstant(loadAddress)) { + if ((loadAddress >> BASE_OFFSET) == GBA_REGION_IO && !GBAIOIsReadConstant(loadAddress)) { gba->idleDetectionStep = -1; return; } - if ((loadAddress >> BASE_OFFSET) < REGION_CART0 || (loadAddress >> BASE_OFFSET) > REGION_CART2_EX) { + if ((loadAddress >> BASE_OFFSET) < GBA_REGION_ROM0 || (loadAddress >> BASE_OFFSET) > GBA_REGION_ROM2_EX) { gba->taintedRegisters[info.op1.reg] = true; } else { switch (info.memory.width) { @@ -232,7 +236,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { struct GBAMemory* memory = &gba->memory; int newRegion = address >> BASE_OFFSET; - if (gba->idleOptimization >= IDLE_LOOP_REMOVE && memory->activeRegion != REGION_BIOS) { + if (gba->idleOptimization >= IDLE_LOOP_REMOVE && memory->activeRegion != GBA_REGION_BIOS) { if (address == gba->idleLoop) { if (gba->haltPending) { gba->haltPending = false; @@ -273,33 +277,33 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { } else { cpu->memory.activeMask &= -WORD_SIZE_ARM; } - if (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize) { + if (newRegion < GBA_REGION_ROM0 || (address & (GBA_SIZE_ROM0 - 1)) < memory->romSize) { return; } } - if (memory->activeRegion == REGION_BIOS) { + if (memory->activeRegion == GBA_REGION_BIOS) { memory->biosPrefetch = cpu->prefetch[1]; } memory->activeRegion = newRegion; switch (newRegion) { - case REGION_BIOS: + case GBA_REGION_BIOS: cpu->memory.activeRegion = memory->bios; - cpu->memory.activeMask = SIZE_BIOS - 1; + cpu->memory.activeMask = GBA_SIZE_BIOS - 1; break; - case REGION_WORKING_RAM: + case GBA_REGION_EWRAM: cpu->memory.activeRegion = memory->wram; - cpu->memory.activeMask = SIZE_WORKING_RAM - 1; + cpu->memory.activeMask = GBA_SIZE_EWRAM - 1; break; - case REGION_WORKING_IRAM: + case GBA_REGION_IWRAM: cpu->memory.activeRegion = memory->iwram; - cpu->memory.activeMask = SIZE_WORKING_IRAM - 1; + cpu->memory.activeMask = GBA_SIZE_IWRAM - 1; break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: cpu->memory.activeRegion = (uint32_t*) gba->video.palette; - cpu->memory.activeMask = SIZE_PALETTE_RAM - 1; + cpu->memory.activeMask = GBA_SIZE_PALETTE_RAM - 1; break; - case REGION_VRAM: + case GBA_REGION_VRAM: if (address & 0x10000) { cpu->memory.activeRegion = (uint32_t*) &gba->video.vram[0x8000]; cpu->memory.activeMask = 0x00007FFF; @@ -308,19 +312,19 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { cpu->memory.activeMask = 0x0000FFFF; } break; - case REGION_OAM: + case GBA_REGION_OAM: cpu->memory.activeRegion = (uint32_t*) gba->video.oam.raw; - cpu->memory.activeMask = SIZE_OAM - 1; + cpu->memory.activeMask = GBA_SIZE_OAM - 1; break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: cpu->memory.activeRegion = memory->rom; cpu->memory.activeMask = memory->romMask; - if ((address & (SIZE_CART0 - 1)) < memory->romSize) { + if ((address & (GBA_SIZE_ROM0 - 1)) < memory->romSize) { break; } if ((address & 0x00FFFFFE) == AGB_PRINT_FLUSH_ADDR && memory->agbPrintProtect == 0x20) { @@ -362,8 +366,8 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { value = GBALoadBad(cpu); #define LOAD_BIOS \ - if (address < SIZE_BIOS) { \ - if (memory->activeRegion == REGION_BIOS) { \ + if (address < GBA_SIZE_BIOS) { \ + if (memory->activeRegion == GBA_REGION_BIOS) { \ LOAD_32(value, address & -4, memory->bios); \ } else { \ mLOG(GBA_MEM, GAME_ERROR, "Bad BIOS Load32: 0x%08X", address); \ @@ -374,20 +378,20 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { value = GBALoadBad(cpu); \ } -#define LOAD_WORKING_RAM \ - LOAD_32(value, address & (SIZE_WORKING_RAM - 4), memory->wram); \ - wait += waitstatesRegion[REGION_WORKING_RAM]; +#define LOAD_EWRAM \ + LOAD_32(value, address & (GBA_SIZE_EWRAM - 4), memory->wram); \ + wait += waitstatesRegion[GBA_REGION_EWRAM]; -#define LOAD_WORKING_IRAM LOAD_32(value, address & (SIZE_WORKING_IRAM - 4), memory->iwram); +#define LOAD_IWRAM LOAD_32(value, address & (GBA_SIZE_IWRAM - 4), memory->iwram); #define LOAD_IO value = GBAIORead(gba, address & OFFSET_MASK & ~3) | (GBAIORead(gba, (address & OFFSET_MASK & ~1) | 2) << 16); #define LOAD_PALETTE_RAM \ - LOAD_32(value, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \ - wait += waitstatesRegion[REGION_PALETTE_RAM]; + LOAD_32(value, address & (GBA_SIZE_PALETTE_RAM - 4), gba->video.palette); \ + wait += waitstatesRegion[GBA_REGION_PALETTE_RAM]; #define LOAD_VRAM \ - if ((address & 0x0001FFFF) >= SIZE_VRAM) { \ - if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \ + if ((address & 0x0001FFFF) >= GBA_SIZE_VRAM) { \ + if ((address & (GBA_SIZE_VRAM | 0x00014000)) == GBA_SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3)) { \ mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load32: 0x%08X", address); \ value = 0; \ } else { \ @@ -397,16 +401,16 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \ } \ ++wait; \ - if (gba->video.shouldStall) { \ + if (gba->video.shouldStall && (address & 0x0001FFFF) < ((GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3) ? 0x00014000 : 0x00010000)) { \ wait += GBAMemoryStallVRAM(gba, wait, 1); \ } -#define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); +#define LOAD_OAM LOAD_32(value, address & (GBA_SIZE_OAM - 4), gba->video.oam.raw); #define LOAD_CART \ wait += waitstatesRegion[address >> BASE_OFFSET]; \ - if ((address & (SIZE_CART0 - 1)) < memory->romSize) { \ - LOAD_32(value, address & (SIZE_CART0 - 4), memory->rom); \ + if ((address & (GBA_SIZE_ROM0 - 4)) < memory->romSize) { \ + LOAD_32(value, address & (GBA_SIZE_ROM0 - 4), memory->rom); \ } else if (memory->vfame.cartType) { \ value = GBAVFameGetPatternValue(address, 32); \ } else { \ @@ -431,13 +435,13 @@ uint32_t GBALoadBad(struct ARMCore* cpu) { if (cpu->executionMode == MODE_THUMB) { /* http://ngemu.com/threads/gba-open-bus.170809/ */ switch (cpu->gprs[ARM_PC] >> BASE_OFFSET) { - case REGION_BIOS: - case REGION_OAM: + case GBA_REGION_BIOS: + case GBA_REGION_OAM: /* This isn't right half the time, but we don't have $+6 handy */ value <<= 16; value |= cpu->prefetch[0]; break; - case REGION_WORKING_IRAM: + case GBA_REGION_IWRAM: /* This doesn't handle prefetch clobbering */ if (cpu->gprs[ARM_PC] & 2) { value <<= 16; @@ -462,37 +466,37 @@ uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { char* waitstatesRegion = memory->waitstatesNonseq32; switch (address >> BASE_OFFSET) { - case REGION_BIOS: + case GBA_REGION_BIOS: LOAD_BIOS; break; - case REGION_WORKING_RAM: - LOAD_WORKING_RAM; + case GBA_REGION_EWRAM: + LOAD_EWRAM; break; - case REGION_WORKING_IRAM: - LOAD_WORKING_IRAM; + case GBA_REGION_IWRAM: + LOAD_IWRAM; break; - case REGION_IO: + case GBA_REGION_IO: LOAD_IO; break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: LOAD_PALETTE_RAM; break; - case REGION_VRAM: + case GBA_REGION_VRAM: LOAD_VRAM; break; - case REGION_OAM: + case GBA_REGION_OAM: LOAD_OAM; break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: LOAD_CART; break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: LOAD_SRAM; break; default: @@ -503,7 +507,7 @@ uint32_t GBALoad32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (cycleCounter) { wait += 2; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -520,9 +524,9 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { int wait = 0; switch (address >> BASE_OFFSET) { - case REGION_BIOS: - if (address < SIZE_BIOS) { - if (memory->activeRegion == REGION_BIOS) { + case GBA_REGION_BIOS: + if (address < GBA_SIZE_BIOS) { + if (memory->activeRegion == GBA_REGION_BIOS) { LOAD_16(value, address & -2, memory->bios); } else { mLOG(GBA_MEM, GAME_ERROR, "Bad BIOS Load16: 0x%08X", address); @@ -533,22 +537,22 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = (GBALoadBad(cpu) >> ((address & 2) * 8)) & 0xFFFF; } break; - case REGION_WORKING_RAM: - LOAD_16(value, address & (SIZE_WORKING_RAM - 2), memory->wram); - wait = memory->waitstatesNonseq16[REGION_WORKING_RAM]; + case GBA_REGION_EWRAM: + LOAD_16(value, address & (GBA_SIZE_EWRAM - 2), memory->wram); + wait = memory->waitstatesNonseq16[GBA_REGION_EWRAM]; break; - case REGION_WORKING_IRAM: - LOAD_16(value, address & (SIZE_WORKING_IRAM - 2), memory->iwram); + case GBA_REGION_IWRAM: + LOAD_16(value, address & (GBA_SIZE_IWRAM - 2), memory->iwram); break; - case REGION_IO: + case GBA_REGION_IO: value = GBAIORead(gba, address & (OFFSET_MASK - 1)); break; - case REGION_PALETTE_RAM: - LOAD_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); + case GBA_REGION_PALETTE_RAM: + LOAD_16(value, address & (GBA_SIZE_PALETTE_RAM - 2), gba->video.palette); break; - case REGION_VRAM: - if ((address & 0x0001FFFF) >= SIZE_VRAM) { - if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { + case GBA_REGION_VRAM: + if ((address & 0x0001FFFF) >= GBA_SIZE_VRAM) { + if ((address & (GBA_SIZE_VRAM | 0x00014000)) == GBA_SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3)) { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load16: 0x%08X", address); value = 0; break; @@ -557,24 +561,24 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { } else { LOAD_16(value, address & 0x0001FFFE, gba->video.vram); } - if (gba->video.shouldStall) { + if (gba->video.shouldStall && (address & 0x0001FFFF) < ((GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3) ? 0x00014000 : 0x00010000)) { wait += GBAMemoryStallVRAM(gba, wait, 0); } break; - case REGION_OAM: - LOAD_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw); + case GBA_REGION_OAM: + LOAD_16(value, address & (GBA_SIZE_OAM - 2), gba->video.oam.raw); break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; - if ((address & (SIZE_CART0 - 1)) < memory->romSize) { - LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); + if ((address & (GBA_SIZE_ROM0 - 2)) < memory->romSize) { + LOAD_16(value, address & (GBA_SIZE_ROM0 - 2), memory->rom); } else if (memory->vfame.cartType) { value = GBAVFameGetPatternValue(address, 16); - } else if ((address & (SIZE_CART0 - 1)) >= AGB_PRINT_BASE) { + } else if ((address & (GBA_SIZE_ROM0 - 2)) >= AGB_PRINT_BASE) { uint32_t agbPrintAddr = address & 0x00FFFFFF; if (agbPrintAddr == AGB_PRINT_PROTECT) { value = memory->agbPrintProtect; @@ -589,14 +593,14 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = (address >> 1) & 0xFFFF; } break; - case REGION_CART2_EX: + case GBA_REGION_ROM2_EX: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512) { value = GBASavedataReadEEPROM(&memory->savedata); } else if ((address & 0x0DFC0000) >= 0x0DF80000 && memory->hw.devices & HW_EREADER) { value = GBACartEReaderRead(&memory->ereader, address); - } else if ((address & (SIZE_CART0 - 1)) < memory->romSize) { - LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); + } else if ((address & (GBA_SIZE_ROM0 - 2)) < memory->romSize) { + LOAD_16(value, address & (GBA_SIZE_ROM0 - 2), memory->rom); } else if (memory->vfame.cartType) { value = GBAVFameGetPatternValue(address, 16); } else { @@ -604,8 +608,8 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = (address >> 1) & 0xFFFF; } break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; value = GBALoad8(cpu, address, 0); value |= value << 8; @@ -618,7 +622,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (cycleCounter) { wait += 2; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -635,9 +639,9 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { int wait = 0; switch (address >> BASE_OFFSET) { - case REGION_BIOS: - if (address < SIZE_BIOS) { - if (memory->activeRegion == REGION_BIOS) { + case GBA_REGION_BIOS: + if (address < GBA_SIZE_BIOS) { + if (memory->activeRegion == GBA_REGION_BIOS) { value = ((uint8_t*) memory->bios)[address]; } else { mLOG(GBA_MEM, GAME_ERROR, "Bad BIOS Load8: 0x%08X", address); @@ -648,22 +652,22 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = (GBALoadBad(cpu) >> ((address & 3) * 8)) & 0xFF; } break; - case REGION_WORKING_RAM: - value = ((uint8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)]; - wait = memory->waitstatesNonseq16[REGION_WORKING_RAM]; + case GBA_REGION_EWRAM: + value = ((uint8_t*) memory->wram)[address & (GBA_SIZE_EWRAM - 1)]; + wait = memory->waitstatesNonseq16[GBA_REGION_EWRAM]; break; - case REGION_WORKING_IRAM: - value = ((uint8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)]; + case GBA_REGION_IWRAM: + value = ((uint8_t*) memory->iwram)[address & (GBA_SIZE_IWRAM - 1)]; break; - case REGION_IO: + case GBA_REGION_IO: value = (GBAIORead(gba, address & 0xFFFE) >> ((address & 0x0001) << 3)) & 0xFF; break; - case REGION_PALETTE_RAM: - value = ((uint8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)]; + case GBA_REGION_PALETTE_RAM: + value = ((uint8_t*) gba->video.palette)[address & (GBA_SIZE_PALETTE_RAM - 1)]; break; - case REGION_VRAM: - if ((address & 0x0001FFFF) >= SIZE_VRAM) { - if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { + case GBA_REGION_VRAM: + if ((address & 0x0001FFFF) >= GBA_SIZE_VRAM) { + if ((address & (GBA_SIZE_VRAM | 0x00014000)) == GBA_SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3)) { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load8: 0x%08X", address); value = 0; break; @@ -676,18 +680,18 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { wait += GBAMemoryStallVRAM(gba, wait, 0); } break; - case REGION_OAM: - value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)]; + case GBA_REGION_OAM: + value = ((uint8_t*) gba->video.oam.raw)[address & (GBA_SIZE_OAM - 1)]; break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; - if ((address & (SIZE_CART0 - 1)) < memory->romSize) { - value = ((uint8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; + if ((address & (GBA_SIZE_ROM0 - 1)) < memory->romSize) { + value = ((uint8_t*) memory->rom)[address & (GBA_SIZE_ROM0 - 1)]; } else if (memory->vfame.cartType) { value = GBAVFameGetPatternValue(address, 8); } else { @@ -695,8 +699,8 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { value = ((address >> 1) >> ((address & 1) * 8)) & 0xFF; } break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: wait = memory->waitstatesNonseq16[address >> BASE_OFFSET]; if (memory->savedata.type == SAVEDATA_AUTODETECT) { mLOG(GBA_MEM, INFO, "Detected SRAM savegame"); @@ -708,13 +712,13 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (memory->hw.devices & HW_EREADER && (address & 0xE00FF80) >= 0xE00FF80) { value = GBACartEReaderReadFlash(&memory->ereader, address); } else if (memory->savedata.type == SAVEDATA_SRAM) { - value = memory->savedata.data[address & (SIZE_CART_SRAM - 1)]; + value = memory->savedata.data[address & (GBA_SIZE_SRAM - 1)]; } else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) { value = GBASavedataReadFlash(&memory->savedata, address); } else if (memory->hw.devices & HW_TILT) { value = GBAHardwareTiltRead(&memory->hw, address & OFFSET_MASK); } else if (memory->savedata.type == SAVEDATA_SRAM512) { - value = memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)]; + value = memory->savedata.data[address & (GBA_SIZE_SRAM512 - 1)]; } else { mLOG(GBA_MEM, GAME_ERROR, "Reading from non-existent SRAM: 0x%08X", address); value = 0xFF; @@ -729,7 +733,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (cycleCounter) { wait += 2; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -737,28 +741,28 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { return value; } -#define STORE_WORKING_RAM \ - STORE_32(value, address & (SIZE_WORKING_RAM - 4), memory->wram); \ - wait += waitstatesRegion[REGION_WORKING_RAM]; +#define STORE_EWRAM \ + STORE_32(value, address & (GBA_SIZE_EWRAM - 4), memory->wram); \ + wait += waitstatesRegion[GBA_REGION_EWRAM]; -#define STORE_WORKING_IRAM \ - STORE_32(value, address & (SIZE_WORKING_IRAM - 4), memory->iwram); +#define STORE_IWRAM \ + STORE_32(value, address & (GBA_SIZE_IWRAM - 4), memory->iwram); #define STORE_IO \ GBAIOWrite32(gba, address & (OFFSET_MASK - 3), value); #define STORE_PALETTE_RAM \ - LOAD_32(oldValue, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \ + LOAD_32(oldValue, address & (GBA_SIZE_PALETTE_RAM - 4), gba->video.palette); \ if (oldValue != value) { \ - STORE_32(value, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \ - gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 4)) + 2, value >> 16); \ - gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 4), value); \ + STORE_32(value, address & (GBA_SIZE_PALETTE_RAM - 4), gba->video.palette); \ + gba->video.renderer->writePalette(gba->video.renderer, (address & (GBA_SIZE_PALETTE_RAM - 4)) + 2, value >> 16); \ + gba->video.renderer->writePalette(gba->video.renderer, address & (GBA_SIZE_PALETTE_RAM - 4), value); \ } \ - wait += waitstatesRegion[REGION_PALETTE_RAM]; + wait += waitstatesRegion[GBA_REGION_PALETTE_RAM]; #define STORE_VRAM \ - if ((address & 0x0001FFFF) >= SIZE_VRAM) { \ - if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \ + if ((address & 0x0001FFFF) >= GBA_SIZE_VRAM) { \ + if ((address & (GBA_SIZE_VRAM | 0x00014000)) == GBA_SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3)) { \ mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store32: 0x%08X", address); \ } else { \ LOAD_32(oldValue, address & 0x00017FFC, gba->video.vram); \ @@ -777,16 +781,16 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { } \ } \ ++wait; \ - if (gba->video.shouldStall) { \ + if (gba->video.shouldStall && (address & 0x0001FFFF) < ((GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3) ? 0x00014000 : 0x00010000)) { \ wait += GBAMemoryStallVRAM(gba, wait, 1); \ } #define STORE_OAM \ - LOAD_32(oldValue, address & (SIZE_OAM - 4), gba->video.oam.raw); \ + LOAD_32(oldValue, address & (GBA_SIZE_OAM - 4), gba->video.oam.raw); \ if (oldValue != value) { \ - STORE_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); \ - gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 4)) >> 1); \ - gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) >> 1) + 1); \ + STORE_32(value, address & (GBA_SIZE_OAM - 4), gba->video.oam.raw); \ + gba->video.renderer->writeOAM(gba->video.renderer, (address & (GBA_SIZE_OAM - 4)) >> 1); \ + gba->video.renderer->writeOAM(gba->video.renderer, ((address & (GBA_SIZE_OAM - 4)) >> 1) + 1); \ } #define STORE_CART \ @@ -818,34 +822,34 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle char* waitstatesRegion = memory->waitstatesNonseq32; switch (address >> BASE_OFFSET) { - case REGION_WORKING_RAM: - STORE_WORKING_RAM; + case GBA_REGION_EWRAM: + STORE_EWRAM; break; - case REGION_WORKING_IRAM: - STORE_WORKING_IRAM + case GBA_REGION_IWRAM: + STORE_IWRAM break; - case REGION_IO: + case GBA_REGION_IO: STORE_IO; break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: STORE_PALETTE_RAM; break; - case REGION_VRAM: + case GBA_REGION_VRAM: STORE_VRAM; break; - case REGION_OAM: + case GBA_REGION_OAM: STORE_OAM; break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: STORE_CART; break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: STORE_SRAM; break; default: @@ -855,7 +859,7 @@ void GBAStore32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle if (cycleCounter) { ++wait; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -869,26 +873,26 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle int16_t oldValue; switch (address >> BASE_OFFSET) { - case REGION_WORKING_RAM: - STORE_16(value, address & (SIZE_WORKING_RAM - 2), memory->wram); - wait = memory->waitstatesNonseq16[REGION_WORKING_RAM]; + case GBA_REGION_EWRAM: + STORE_16(value, address & (GBA_SIZE_EWRAM - 2), memory->wram); + wait = memory->waitstatesNonseq16[GBA_REGION_EWRAM]; break; - case REGION_WORKING_IRAM: - STORE_16(value, address & (SIZE_WORKING_IRAM - 2), memory->iwram); + case GBA_REGION_IWRAM: + STORE_16(value, address & (GBA_SIZE_IWRAM - 2), memory->iwram); break; - case REGION_IO: + case GBA_REGION_IO: GBAIOWrite(gba, address & (OFFSET_MASK - 1), value); break; - case REGION_PALETTE_RAM: - LOAD_16(oldValue, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); + case GBA_REGION_PALETTE_RAM: + LOAD_16(oldValue, address & (GBA_SIZE_PALETTE_RAM - 2), gba->video.palette); if (oldValue != value) { - STORE_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); - gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 2), value); + STORE_16(value, address & (GBA_SIZE_PALETTE_RAM - 2), gba->video.palette); + gba->video.renderer->writePalette(gba->video.renderer, address & (GBA_SIZE_PALETTE_RAM - 2), value); } break; - case REGION_VRAM: - if ((address & 0x0001FFFF) >= SIZE_VRAM) { - if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { + case GBA_REGION_VRAM: + if ((address & 0x0001FFFF) >= GBA_SIZE_VRAM) { + if ((address & (GBA_SIZE_VRAM | 0x00014000)) == GBA_SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3)) { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store16: 0x%08X", address); break; } @@ -904,18 +908,18 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE); } } - if (gba->video.shouldStall) { + if (gba->video.shouldStall && (address & 0x0001FFFF) < ((GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3) ? 0x00014000 : 0x00010000)) { wait += GBAMemoryStallVRAM(gba, wait, 0); } break; - case REGION_OAM: - LOAD_16(oldValue, address & (SIZE_OAM - 2), gba->video.oam.raw); + case GBA_REGION_OAM: + LOAD_16(oldValue, address & (GBA_SIZE_OAM - 2), gba->video.oam.raw); if (value != oldValue) { - STORE_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw); - gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 2)) >> 1); + STORE_16(value, address & (GBA_SIZE_OAM - 2), gba->video.oam.raw); + gba->video.renderer->writeOAM(gba->video.renderer, (address & (GBA_SIZE_OAM - 2)) >> 1); } break; - case REGION_CART0: + case GBA_REGION_ROM0: if (IS_GPIO_REGISTER(address & 0xFFFFFE)) { if (memory->hw.devices == HW_NONE) { mLOG(GBA_HW, WARN, "Write to GPIO address %08X on cartridge without GPIO", address); @@ -930,22 +934,22 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle break; } // Fall through - case REGION_CART0_EX: + case GBA_REGION_ROM0_EX: if ((address & 0x00FFFFFF) >= AGB_PRINT_BASE) { uint32_t agbPrintAddr = address & 0x00FFFFFF; if (agbPrintAddr == AGB_PRINT_PROTECT) { memory->agbPrintProtect = value; if (!memory->agbPrintBuffer) { - memory->agbPrintBuffer = anonymousMemoryMap(SIZE_AGB_PRINT); - if (memory->romSize >= SIZE_CART0 / 2) { + memory->agbPrintBuffer = anonymousMemoryMap(GBA_SIZE_AGB_PRINT); + if (memory->romSize >= GBA_SIZE_ROM0 / 2) { int base = 0; - if (memory->romSize == SIZE_CART0) { + if (memory->romSize == GBA_SIZE_ROM0) { base = address & 0x01000000; } memory->agbPrintBase = base; - memory->agbPrintBufferBackup = anonymousMemoryMap(SIZE_AGB_PRINT); - memcpy(memory->agbPrintBufferBackup, &memory->rom[(AGB_PRINT_TOP | base) >> 2], SIZE_AGB_PRINT); + memory->agbPrintBufferBackup = anonymousMemoryMap(GBA_SIZE_AGB_PRINT); + memcpy(memory->agbPrintBufferBackup, &memory->rom[(AGB_PRINT_TOP | base) >> 2], GBA_SIZE_AGB_PRINT); LOAD_16(memory->agbPrintProtectBackup, AGB_PRINT_PROTECT | base, memory->rom); LOAD_16(memory->agbPrintCtxBackup.request, AGB_PRINT_STRUCT | base, memory->rom); LOAD_16(memory->agbPrintCtxBackup.bank, (AGB_PRINT_STRUCT | base) + 2, memory->rom); @@ -967,7 +971,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle } mLOG(GBA_MEM, GAME_ERROR, "Bad cartridge Store16: 0x%08X", address); break; - case REGION_CART2_EX: + case GBA_REGION_ROM2_EX: if ((address & 0x0DFC0000) >= 0x0DF80000 && memory->hw.devices & HW_EREADER) { GBACartEReaderWrite(&memory->ereader, address, value); break; @@ -981,8 +985,8 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle } mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store16: 0x%08X", address); break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: if (address & 1) { mLOG(GBA_MEM, GAME_ERROR, "Unaligned SRAM Store16: 0x%08X", address); break; @@ -997,7 +1001,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle if (cycleCounter) { ++wait; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1011,21 +1015,21 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo uint16_t oldValue; switch (address >> BASE_OFFSET) { - case REGION_WORKING_RAM: - ((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)] = value; - wait = memory->waitstatesNonseq16[REGION_WORKING_RAM]; + case GBA_REGION_EWRAM: + ((int8_t*) memory->wram)[address & (GBA_SIZE_EWRAM - 1)] = value; + wait = memory->waitstatesNonseq16[GBA_REGION_EWRAM]; break; - case REGION_WORKING_IRAM: - ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value; + case GBA_REGION_IWRAM: + ((int8_t*) memory->iwram)[address & (GBA_SIZE_IWRAM - 1)] = value; break; - case REGION_IO: + case GBA_REGION_IO: GBAIOWrite8(gba, address & OFFSET_MASK, value); break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: GBAStore16(cpu, address & ~1, ((uint8_t) value) | ((uint8_t) value << 8), cycleCounter); break; - case REGION_VRAM: - if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) { + case GBA_REGION_VRAM: + if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[GBA_REG(DISPCNT)]) >= 3) ? 0x00014000 : 0x00010000)) { mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); break; } @@ -1038,14 +1042,14 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo wait += GBAMemoryStallVRAM(gba, wait, 0); } break; - case REGION_OAM: + case GBA_REGION_OAM: mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OAM: 0x%08X", address); break; - case REGION_CART0: + case GBA_REGION_ROM0: mLOG(GBA_MEM, STUB, "Unimplemented memory Store8: 0x%08X", address); break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: if (memory->savedata.type == SAVEDATA_AUTODETECT) { if (address == SAVEDATA_FLASH_BASE) { mLOG(GBA_MEM, INFO, "Detected Flash savegame"); @@ -1063,18 +1067,18 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo if (memory->vfame.cartType) { GBAVFameSramWrite(&memory->vfame, address, value, memory->savedata.data); } else { - memory->savedata.data[address & (SIZE_CART_SRAM - 1)] = value; + memory->savedata.data[address & (GBA_SIZE_SRAM - 1)] = value; } memory->savedata.dirty |= mSAVEDATA_DIRT_NEW; } else if (memory->hw.devices & HW_TILT) { GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value); } else if (memory->savedata.type == SAVEDATA_SRAM512) { - memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)] = value; + memory->savedata.data[address & (GBA_SIZE_SRAM512 - 1)] = value; memory->savedata.dirty |= mSAVEDATA_DIRT_NEW; } else { mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } - wait = memory->waitstatesNonseq16[REGION_CART_SRAM]; + wait = memory->waitstatesNonseq16[GBA_REGION_SRAM]; break; default: mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store8: 0x%08X", address); @@ -1083,7 +1087,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo if (cycleCounter) { ++wait; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1095,31 +1099,31 @@ uint32_t GBAView32(struct ARMCore* cpu, uint32_t address) { uint32_t value = 0; address &= ~3; switch (address >> BASE_OFFSET) { - case REGION_BIOS: - if (address < SIZE_BIOS) { + case GBA_REGION_BIOS: + if (address < GBA_SIZE_BIOS) { LOAD_32(value, address, gba->memory.bios); } break; - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_PALETTE_RAM: - case REGION_VRAM: - case REGION_OAM: - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_PALETTE_RAM: + case GBA_REGION_VRAM: + case GBA_REGION_OAM: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: value = GBALoad32(cpu, address, 0); break; - case REGION_IO: - if ((address & OFFSET_MASK) < REG_MAX) { + case GBA_REGION_IO: + if ((address & OFFSET_MASK) < GBA_REG_MAX) { value = gba->memory.io[(address & OFFSET_MASK) >> 1]; value |= gba->memory.io[((address & OFFSET_MASK) >> 1) + 1] << 16; } break; - case REGION_CART_SRAM: + case GBA_REGION_SRAM: value = GBALoad8(cpu, address, 0); value |= GBALoad8(cpu, address + 1, 0) << 8; value |= GBALoad8(cpu, address + 2, 0) << 16; @@ -1136,30 +1140,30 @@ uint16_t GBAView16(struct ARMCore* cpu, uint32_t address) { uint16_t value = 0; address &= ~1; switch (address >> BASE_OFFSET) { - case REGION_BIOS: - if (address < SIZE_BIOS) { + case GBA_REGION_BIOS: + if (address < GBA_SIZE_BIOS) { LOAD_16(value, address, gba->memory.bios); } break; - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_PALETTE_RAM: - case REGION_VRAM: - case REGION_OAM: - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_PALETTE_RAM: + case GBA_REGION_VRAM: + case GBA_REGION_OAM: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: value = GBALoad16(cpu, address, 0); break; - case REGION_IO: - if ((address & OFFSET_MASK) < REG_MAX) { + case GBA_REGION_IO: + if ((address & OFFSET_MASK) < GBA_REG_MAX) { value = gba->memory.io[(address & OFFSET_MASK) >> 1]; } break; - case REGION_CART_SRAM: + case GBA_REGION_SRAM: value = GBALoad8(cpu, address, 0); value |= GBALoad8(cpu, address + 1, 0) << 8; break; @@ -1173,26 +1177,26 @@ uint8_t GBAView8(struct ARMCore* cpu, uint32_t address) { struct GBA* gba = (struct GBA*) cpu->master; uint8_t value = 0; switch (address >> BASE_OFFSET) { - case REGION_BIOS: - if (address < SIZE_BIOS) { + case GBA_REGION_BIOS: + if (address < GBA_SIZE_BIOS) { value = ((uint8_t*) gba->memory.bios)[address]; } break; - case REGION_WORKING_RAM: - case REGION_WORKING_IRAM: - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: - case REGION_CART_SRAM: + case GBA_REGION_EWRAM: + case GBA_REGION_IWRAM: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: + case GBA_REGION_SRAM: value = GBALoad8(cpu, address, 0); break; - case REGION_IO: - case REGION_PALETTE_RAM: - case REGION_VRAM: - case REGION_OAM: + case GBA_REGION_IO: + case GBA_REGION_PALETTE_RAM: + case GBA_REGION_VRAM: + case GBA_REGION_OAM: value = GBAView16(cpu, address) >> ((address & 1) * 8); break; default: @@ -1207,25 +1211,25 @@ void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* o int32_t oldValue = -1; switch (address >> BASE_OFFSET) { - case REGION_WORKING_RAM: - LOAD_32(oldValue, address & (SIZE_WORKING_RAM - 4), memory->wram); - STORE_32(value, address & (SIZE_WORKING_RAM - 4), memory->wram); + case GBA_REGION_EWRAM: + LOAD_32(oldValue, address & (GBA_SIZE_EWRAM - 4), memory->wram); + STORE_32(value, address & (GBA_SIZE_EWRAM - 4), memory->wram); break; - case REGION_WORKING_IRAM: - LOAD_32(oldValue, address & (SIZE_WORKING_IRAM - 4), memory->iwram); - STORE_32(value, address & (SIZE_WORKING_IRAM - 4), memory->iwram); + case GBA_REGION_IWRAM: + LOAD_32(oldValue, address & (GBA_SIZE_IWRAM - 4), memory->iwram); + STORE_32(value, address & (GBA_SIZE_IWRAM - 4), memory->iwram); break; - case REGION_IO: + case GBA_REGION_IO: mLOG(GBA_MEM, STUB, "Unimplemented memory Patch32: 0x%08X", address); break; - case REGION_PALETTE_RAM: - LOAD_32(oldValue, address & (SIZE_PALETTE_RAM - 1), gba->video.palette); - STORE_32(value, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); - gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 4), value); - gba->video.renderer->writePalette(gba->video.renderer, (address & (SIZE_PALETTE_RAM - 4)) + 2, value >> 16); + case GBA_REGION_PALETTE_RAM: + LOAD_32(oldValue, address & (GBA_SIZE_PALETTE_RAM - 4), gba->video.palette); + STORE_32(value, address & (GBA_SIZE_PALETTE_RAM - 4), gba->video.palette); + gba->video.renderer->writePalette(gba->video.renderer, address & (GBA_SIZE_PALETTE_RAM - 4), value); + gba->video.renderer->writePalette(gba->video.renderer, (address & (GBA_SIZE_PALETTE_RAM - 4)) + 2, value >> 16); break; - case REGION_VRAM: - if ((address & 0x0001FFFF) < SIZE_VRAM) { + case GBA_REGION_VRAM: + if ((address & 0x0001FFFF) < GBA_SIZE_VRAM) { LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); STORE_32(value, address & 0x0001FFFC, gba->video.vram); gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFC); @@ -1237,31 +1241,31 @@ void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* o gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) | 2); } break; - case REGION_OAM: - LOAD_32(oldValue, address & (SIZE_OAM - 4), gba->video.oam.raw); - STORE_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); - gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 4)) >> 1); - gba->video.renderer->writeOAM(gba->video.renderer, ((address & (SIZE_OAM - 4)) + 2) >> 1); + case GBA_REGION_OAM: + LOAD_32(oldValue, address & (GBA_SIZE_OAM - 4), gba->video.oam.raw); + STORE_32(value, address & (GBA_SIZE_OAM - 4), gba->video.oam.raw); + gba->video.renderer->writeOAM(gba->video.renderer, (address & (GBA_SIZE_OAM - 4)) >> 1); + gba->video.renderer->writeOAM(gba->video.renderer, ((address & (GBA_SIZE_OAM - 4)) + 2) >> 1); break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: _pristineCow(gba); - if ((address & (SIZE_CART0 - 4)) >= gba->memory.romSize) { - gba->memory.romSize = (address & (SIZE_CART0 - 4)) + 4; + if ((address & (GBA_SIZE_ROM0 - 4)) >= gba->memory.romSize) { + gba->memory.romSize = (address & (GBA_SIZE_ROM0 - 4)) + 4; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; } - LOAD_32(oldValue, address & (SIZE_CART0 - 4), gba->memory.rom); - STORE_32(value, address & (SIZE_CART0 - 4), gba->memory.rom); + LOAD_32(oldValue, address & (GBA_SIZE_ROM0 - 4), gba->memory.rom); + STORE_32(value, address & (GBA_SIZE_ROM0 - 4), gba->memory.rom); break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: if (memory->savedata.type == SAVEDATA_SRAM) { - LOAD_32(oldValue, address & (SIZE_CART_SRAM - 4), memory->savedata.data); - STORE_32(value, address & (SIZE_CART_SRAM - 4), memory->savedata.data); + LOAD_32(oldValue, address & (GBA_SIZE_SRAM - 4), memory->savedata.data); + STORE_32(value, address & (GBA_SIZE_SRAM - 4), memory->savedata.data); } else { mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } @@ -1281,24 +1285,24 @@ void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* o int16_t oldValue = -1; switch (address >> BASE_OFFSET) { - case REGION_WORKING_RAM: - LOAD_16(oldValue, address & (SIZE_WORKING_RAM - 2), memory->wram); - STORE_16(value, address & (SIZE_WORKING_RAM - 2), memory->wram); + case GBA_REGION_EWRAM: + LOAD_16(oldValue, address & (GBA_SIZE_EWRAM - 2), memory->wram); + STORE_16(value, address & (GBA_SIZE_EWRAM - 2), memory->wram); break; - case REGION_WORKING_IRAM: - LOAD_16(oldValue, address & (SIZE_WORKING_IRAM - 2), memory->iwram); - STORE_16(value, address & (SIZE_WORKING_IRAM - 2), memory->iwram); + case GBA_REGION_IWRAM: + LOAD_16(oldValue, address & (GBA_SIZE_IWRAM - 2), memory->iwram); + STORE_16(value, address & (GBA_SIZE_IWRAM - 2), memory->iwram); break; - case REGION_IO: + case GBA_REGION_IO: mLOG(GBA_MEM, STUB, "Unimplemented memory Patch16: 0x%08X", address); break; - case REGION_PALETTE_RAM: - LOAD_16(oldValue, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); - STORE_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); - gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 2), value); + case GBA_REGION_PALETTE_RAM: + LOAD_16(oldValue, address & (GBA_SIZE_PALETTE_RAM - 2), gba->video.palette); + STORE_16(value, address & (GBA_SIZE_PALETTE_RAM - 2), gba->video.palette); + gba->video.renderer->writePalette(gba->video.renderer, address & (GBA_SIZE_PALETTE_RAM - 2), value); break; - case REGION_VRAM: - if ((address & 0x0001FFFF) < SIZE_VRAM) { + case GBA_REGION_VRAM: + if ((address & 0x0001FFFF) < GBA_SIZE_VRAM) { LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram); STORE_16(value, address & 0x0001FFFE, gba->video.vram); gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE); @@ -1308,30 +1312,30 @@ void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* o gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE); } break; - case REGION_OAM: - LOAD_16(oldValue, address & (SIZE_OAM - 2), gba->video.oam.raw); - STORE_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw); - gba->video.renderer->writeOAM(gba->video.renderer, (address & (SIZE_OAM - 2)) >> 1); + case GBA_REGION_OAM: + LOAD_16(oldValue, address & (GBA_SIZE_OAM - 2), gba->video.oam.raw); + STORE_16(value, address & (GBA_SIZE_OAM - 2), gba->video.oam.raw); + gba->video.renderer->writeOAM(gba->video.renderer, (address & (GBA_SIZE_OAM - 2)) >> 1); break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: _pristineCow(gba); - if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) { - gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2; + if ((address & (GBA_SIZE_ROM0 - 2)) >= gba->memory.romSize) { + gba->memory.romSize = (address & (GBA_SIZE_ROM0 - 2)) + 2; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; } - LOAD_16(oldValue, address & (SIZE_CART0 - 2), gba->memory.rom); - STORE_16(value, address & (SIZE_CART0 - 2), gba->memory.rom); + LOAD_16(oldValue, address & (GBA_SIZE_ROM0 - 2), gba->memory.rom); + STORE_16(value, address & (GBA_SIZE_ROM0 - 2), gba->memory.rom); break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: if (memory->savedata.type == SAVEDATA_SRAM) { - LOAD_16(oldValue, address & (SIZE_CART_SRAM - 2), memory->savedata.data); - STORE_16(value, address & (SIZE_CART_SRAM - 2), memory->savedata.data); + LOAD_16(oldValue, address & (GBA_SIZE_SRAM - 2), memory->savedata.data); + STORE_16(value, address & (GBA_SIZE_SRAM - 2), memory->savedata.data); } else { mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } @@ -1351,45 +1355,45 @@ void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old) int8_t oldValue = -1; switch (address >> BASE_OFFSET) { - case REGION_WORKING_RAM: - oldValue = ((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)]; - ((int8_t*) memory->wram)[address & (SIZE_WORKING_RAM - 1)] = value; + case GBA_REGION_EWRAM: + oldValue = ((int8_t*) memory->wram)[address & (GBA_SIZE_EWRAM - 1)]; + ((int8_t*) memory->wram)[address & (GBA_SIZE_EWRAM - 1)] = value; break; - case REGION_WORKING_IRAM: - oldValue = ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)]; - ((int8_t*) memory->iwram)[address & (SIZE_WORKING_IRAM - 1)] = value; + case GBA_REGION_IWRAM: + oldValue = ((int8_t*) memory->iwram)[address & (GBA_SIZE_IWRAM - 1)]; + ((int8_t*) memory->iwram)[address & (GBA_SIZE_IWRAM - 1)] = value; break; - case REGION_IO: + case GBA_REGION_IO: mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; - case REGION_VRAM: + case GBA_REGION_VRAM: mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; - case REGION_OAM: + case GBA_REGION_OAM: mLOG(GBA_MEM, STUB, "Unimplemented memory Patch8: 0x%08X", address); break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: _pristineCow(gba); - if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) { - gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2; + if ((address & (GBA_SIZE_ROM0 - 1)) >= gba->memory.romSize) { + gba->memory.romSize = (address & (GBA_SIZE_ROM0 - 2)) + 2; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; } - oldValue = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; - ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)] = value; + oldValue = ((int8_t*) memory->rom)[address & (GBA_SIZE_ROM0 - 1)]; + ((int8_t*) memory->rom)[address & (GBA_SIZE_ROM0 - 1)] = value; break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: if (memory->savedata.type == SAVEDATA_SRAM) { - oldValue = ((int8_t*) memory->savedata.data)[address & (SIZE_CART_SRAM - 1)]; - ((int8_t*) memory->savedata.data)[address & (SIZE_CART_SRAM - 1)] = value; + oldValue = ((int8_t*) memory->savedata.data)[address & (GBA_SIZE_SRAM - 1)]; + ((int8_t*) memory->savedata.data)[address & (GBA_SIZE_SRAM - 1)] = value; } else { mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address); } @@ -1458,43 +1462,43 @@ uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L uint32_t addressMisalign = address & 0x3; int region = address >> BASE_OFFSET; - if (region < REGION_CART_SRAM) { + if (region < GBA_REGION_SRAM) { address &= 0xFFFFFFFC; } int wait = memory->waitstatesSeq32[region] - memory->waitstatesNonseq32[region]; switch (region) { - case REGION_BIOS: + case GBA_REGION_BIOS: LDM_LOOP(LOAD_BIOS); break; - case REGION_WORKING_RAM: - LDM_LOOP(LOAD_WORKING_RAM); + case GBA_REGION_EWRAM: + LDM_LOOP(LOAD_EWRAM); break; - case REGION_WORKING_IRAM: - LDM_LOOP(LOAD_WORKING_IRAM); + case GBA_REGION_IWRAM: + LDM_LOOP(LOAD_IWRAM); break; - case REGION_IO: + case GBA_REGION_IO: LDM_LOOP(LOAD_IO); break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: LDM_LOOP(LOAD_PALETTE_RAM); break; - case REGION_VRAM: + case GBA_REGION_VRAM: LDM_LOOP(LOAD_VRAM); break; - case REGION_OAM: + case GBA_REGION_OAM: LDM_LOOP(LOAD_OAM); break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: LDM_LOOP(LOAD_CART); break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: LDM_LOOP(LOAD_SRAM); break; default: @@ -1504,7 +1508,7 @@ uint32_t GBALoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L if (cycleCounter) { ++wait; - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1580,40 +1584,40 @@ uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum uint32_t addressMisalign = address & 0x3; int region = address >> BASE_OFFSET; - if (region < REGION_CART_SRAM) { + if (region < GBA_REGION_SRAM) { address &= 0xFFFFFFFC; } int wait = memory->waitstatesSeq32[region] - memory->waitstatesNonseq32[region]; switch (region) { - case REGION_WORKING_RAM: - STM_LOOP(STORE_WORKING_RAM); + case GBA_REGION_EWRAM: + STM_LOOP(STORE_EWRAM); break; - case REGION_WORKING_IRAM: - STM_LOOP(STORE_WORKING_IRAM); + case GBA_REGION_IWRAM: + STM_LOOP(STORE_IWRAM); break; - case REGION_IO: + case GBA_REGION_IO: STM_LOOP(STORE_IO); break; - case REGION_PALETTE_RAM: + case GBA_REGION_PALETTE_RAM: STM_LOOP(STORE_PALETTE_RAM); break; - case REGION_VRAM: + case GBA_REGION_VRAM: STM_LOOP(STORE_VRAM); break; - case REGION_OAM: + case GBA_REGION_OAM: STM_LOOP(STORE_OAM); break; - case REGION_CART0: - case REGION_CART0_EX: - case REGION_CART1: - case REGION_CART1_EX: - case REGION_CART2: - case REGION_CART2_EX: + case GBA_REGION_ROM0: + case GBA_REGION_ROM0_EX: + case GBA_REGION_ROM1: + case GBA_REGION_ROM1_EX: + case GBA_REGION_ROM2: + case GBA_REGION_ROM2_EX: STM_LOOP(STORE_CART); break; - case REGION_CART_SRAM: - case REGION_CART_SRAM_MIRROR: + case GBA_REGION_SRAM: + case GBA_REGION_SRAM_MIRROR: STM_LOOP(STORE_SRAM); break; default: @@ -1622,7 +1626,7 @@ uint32_t GBAStoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum } if (cycleCounter) { - if (address < BASE_CART0) { + if (address < GBA_BASE_ROM0) { wait = GBAMemoryStall(cpu, wait); } *cycleCounter += wait; @@ -1651,26 +1655,26 @@ void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) { int ws2seq = (parameters & 0x0400) >> 10; int prefetch = parameters & 0x4000; - memory->waitstatesNonseq16[REGION_CART_SRAM] = memory->waitstatesNonseq16[REGION_CART_SRAM_MIRROR] = GBA_ROM_WAITSTATES[sram]; - memory->waitstatesSeq16[REGION_CART_SRAM] = memory->waitstatesSeq16[REGION_CART_SRAM_MIRROR] = GBA_ROM_WAITSTATES[sram]; - memory->waitstatesNonseq32[REGION_CART_SRAM] = memory->waitstatesNonseq32[REGION_CART_SRAM_MIRROR] = 2 * GBA_ROM_WAITSTATES[sram] + 1; - memory->waitstatesSeq32[REGION_CART_SRAM] = memory->waitstatesSeq32[REGION_CART_SRAM_MIRROR] = 2 * GBA_ROM_WAITSTATES[sram] + 1; + memory->waitstatesNonseq16[GBA_REGION_SRAM] = memory->waitstatesNonseq16[GBA_REGION_SRAM_MIRROR] = GBA_ROM_WAITSTATES[sram]; + memory->waitstatesSeq16[GBA_REGION_SRAM] = memory->waitstatesSeq16[GBA_REGION_SRAM_MIRROR] = GBA_ROM_WAITSTATES[sram]; + memory->waitstatesNonseq32[GBA_REGION_SRAM] = memory->waitstatesNonseq32[GBA_REGION_SRAM_MIRROR] = 2 * GBA_ROM_WAITSTATES[sram] + 1; + memory->waitstatesSeq32[GBA_REGION_SRAM] = memory->waitstatesSeq32[GBA_REGION_SRAM_MIRROR] = 2 * GBA_ROM_WAITSTATES[sram] + 1; - memory->waitstatesNonseq16[REGION_CART0] = memory->waitstatesNonseq16[REGION_CART0_EX] = GBA_ROM_WAITSTATES[ws0]; - memory->waitstatesNonseq16[REGION_CART1] = memory->waitstatesNonseq16[REGION_CART1_EX] = GBA_ROM_WAITSTATES[ws1]; - memory->waitstatesNonseq16[REGION_CART2] = memory->waitstatesNonseq16[REGION_CART2_EX] = GBA_ROM_WAITSTATES[ws2]; + memory->waitstatesNonseq16[GBA_REGION_ROM0] = memory->waitstatesNonseq16[GBA_REGION_ROM0_EX] = GBA_ROM_WAITSTATES[ws0]; + memory->waitstatesNonseq16[GBA_REGION_ROM1] = memory->waitstatesNonseq16[GBA_REGION_ROM1_EX] = GBA_ROM_WAITSTATES[ws1]; + memory->waitstatesNonseq16[GBA_REGION_ROM2] = memory->waitstatesNonseq16[GBA_REGION_ROM2_EX] = GBA_ROM_WAITSTATES[ws2]; - memory->waitstatesSeq16[REGION_CART0] = memory->waitstatesSeq16[REGION_CART0_EX] = GBA_ROM_WAITSTATES_SEQ[ws0seq]; - memory->waitstatesSeq16[REGION_CART1] = memory->waitstatesSeq16[REGION_CART1_EX] = GBA_ROM_WAITSTATES_SEQ[ws1seq + 2]; - memory->waitstatesSeq16[REGION_CART2] = memory->waitstatesSeq16[REGION_CART2_EX] = GBA_ROM_WAITSTATES_SEQ[ws2seq + 4]; + memory->waitstatesSeq16[GBA_REGION_ROM0] = memory->waitstatesSeq16[GBA_REGION_ROM0_EX] = GBA_ROM_WAITSTATES_SEQ[ws0seq]; + memory->waitstatesSeq16[GBA_REGION_ROM1] = memory->waitstatesSeq16[GBA_REGION_ROM1_EX] = GBA_ROM_WAITSTATES_SEQ[ws1seq + 2]; + memory->waitstatesSeq16[GBA_REGION_ROM2] = memory->waitstatesSeq16[GBA_REGION_ROM2_EX] = GBA_ROM_WAITSTATES_SEQ[ws2seq + 4]; - memory->waitstatesNonseq32[REGION_CART0] = memory->waitstatesNonseq32[REGION_CART0_EX] = memory->waitstatesNonseq16[REGION_CART0] + 1 + memory->waitstatesSeq16[REGION_CART0]; - memory->waitstatesNonseq32[REGION_CART1] = memory->waitstatesNonseq32[REGION_CART1_EX] = memory->waitstatesNonseq16[REGION_CART1] + 1 + memory->waitstatesSeq16[REGION_CART1]; - memory->waitstatesNonseq32[REGION_CART2] = memory->waitstatesNonseq32[REGION_CART2_EX] = memory->waitstatesNonseq16[REGION_CART2] + 1 + memory->waitstatesSeq16[REGION_CART2]; + memory->waitstatesNonseq32[GBA_REGION_ROM0] = memory->waitstatesNonseq32[GBA_REGION_ROM0_EX] = memory->waitstatesNonseq16[GBA_REGION_ROM0] + 1 + memory->waitstatesSeq16[GBA_REGION_ROM0]; + memory->waitstatesNonseq32[GBA_REGION_ROM1] = memory->waitstatesNonseq32[GBA_REGION_ROM1_EX] = memory->waitstatesNonseq16[GBA_REGION_ROM1] + 1 + memory->waitstatesSeq16[GBA_REGION_ROM1]; + memory->waitstatesNonseq32[GBA_REGION_ROM2] = memory->waitstatesNonseq32[GBA_REGION_ROM2_EX] = memory->waitstatesNonseq16[GBA_REGION_ROM2] + 1 + memory->waitstatesSeq16[GBA_REGION_ROM2]; - memory->waitstatesSeq32[REGION_CART0] = memory->waitstatesSeq32[REGION_CART0_EX] = 2 * memory->waitstatesSeq16[REGION_CART0] + 1; - memory->waitstatesSeq32[REGION_CART1] = memory->waitstatesSeq32[REGION_CART1_EX] = 2 * memory->waitstatesSeq16[REGION_CART1] + 1; - memory->waitstatesSeq32[REGION_CART2] = memory->waitstatesSeq32[REGION_CART2_EX] = 2 * memory->waitstatesSeq16[REGION_CART2] + 1; + memory->waitstatesSeq32[GBA_REGION_ROM0] = memory->waitstatesSeq32[GBA_REGION_ROM0_EX] = 2 * memory->waitstatesSeq16[GBA_REGION_ROM0] + 1; + memory->waitstatesSeq32[GBA_REGION_ROM1] = memory->waitstatesSeq32[GBA_REGION_ROM1_EX] = 2 * memory->waitstatesSeq16[GBA_REGION_ROM1] + 1; + memory->waitstatesSeq32[GBA_REGION_ROM2] = memory->waitstatesSeq32[GBA_REGION_ROM2_EX] = 2 * memory->waitstatesSeq16[GBA_REGION_ROM2] + 1; memory->prefetch = prefetch; @@ -1684,7 +1688,7 @@ void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) { int phi = (parameters >> 11) & 3; uint32_t base = memory->agbPrintBase; if (phi == 3) { - memcpy(&memory->rom[(AGB_PRINT_TOP | base) >> 2], memory->agbPrintBuffer, SIZE_AGB_PRINT); + memcpy(&memory->rom[(AGB_PRINT_TOP | base) >> 2], memory->agbPrintBuffer, GBA_SIZE_AGB_PRINT); STORE_16(memory->agbPrintProtect, AGB_PRINT_PROTECT | base, memory->rom); STORE_16(memory->agbPrintCtx.request, AGB_PRINT_STRUCT | base, memory->rom); STORE_16(memory->agbPrintCtx.bank, (AGB_PRINT_STRUCT | base) + 2, memory->rom); @@ -1692,7 +1696,7 @@ void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) { STORE_16(memory->agbPrintCtx.put, (AGB_PRINT_STRUCT | base) + 6, memory->rom); STORE_32(_agbPrintFunc, AGB_PRINT_FLUSH_ADDR | base, memory->rom); } else { - memcpy(&memory->rom[(AGB_PRINT_TOP | base) >> 2], memory->agbPrintBufferBackup, SIZE_AGB_PRINT); + memcpy(&memory->rom[(AGB_PRINT_TOP | base) >> 2], memory->agbPrintBufferBackup, GBA_SIZE_AGB_PRINT); STORE_16(memory->agbPrintProtectBackup, AGB_PRINT_PROTECT | base, memory->rom); STORE_16(memory->agbPrintCtxBackup.request, AGB_PRINT_STRUCT | base, memory->rom); STORE_16(memory->agbPrintCtxBackup.bank, (AGB_PRINT_STRUCT | base) + 2, memory->rom); @@ -1709,10 +1713,10 @@ void GBAAdjustEWRAMWaitstates(struct GBA* gba, uint16_t parameters) { int wait = 15 - ((parameters >> 8) & 0xF); if (wait) { - memory->waitstatesNonseq16[REGION_WORKING_RAM] = wait; - memory->waitstatesSeq16[REGION_WORKING_RAM] = wait; - memory->waitstatesNonseq32[REGION_WORKING_RAM] = 2 * wait + 1; - memory->waitstatesSeq32[REGION_WORKING_RAM] = 2 * wait + 1; + memory->waitstatesNonseq16[GBA_REGION_EWRAM] = wait; + memory->waitstatesSeq16[GBA_REGION_EWRAM] = wait; + memory->waitstatesNonseq32[GBA_REGION_EWRAM] = 2 * wait + 1; + memory->waitstatesSeq32[GBA_REGION_EWRAM] = 2 * wait + 1; cpu->memory.activeSeqCycles32 = memory->waitstatesSeq32[memory->activeRegion]; cpu->memory.activeSeqCycles16 = memory->waitstatesSeq16[memory->activeRegion]; @@ -1732,7 +1736,7 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) { struct GBA* gba = (struct GBA*) cpu->master; struct GBAMemory* memory = &gba->memory; - if (memory->activeRegion < REGION_CART0 || !memory->prefetch) { + if (memory->activeRegion < GBA_REGION_ROM0 || !memory->prefetch) { // The wait is the stall return wait; } @@ -1747,15 +1751,13 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) { maxLoads -= previousLoads; } - int32_t s = cpu->memory.activeSeqCycles16; - int32_t n2s = cpu->memory.activeNonseqCycles16 - cpu->memory.activeSeqCycles16 + 1; - // Figure out how many sequential loads we can jam in + int32_t s = cpu->memory.activeSeqCycles16; int32_t stall = s + 1; int32_t loads = 1; while (stall < wait && loads < maxLoads) { - stall += s; + stall += s + 1; ++loads; } memory->lastPrefetchedPc = cpu->gprs[ARM_PC] + WORD_SIZE_THUMB * (loads + previousLoads - 1); @@ -1766,10 +1768,10 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) { } // This instruction used to have an N, convert it to an S. - wait -= n2s; + wait -= cpu->memory.activeNonseqCycles16 - s; // The next |loads|S waitstates disappear entirely, so long as they're all in a row - wait -= stall - 1; + wait -= stall; return wait; } @@ -1777,7 +1779,7 @@ int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) { int32_t GBAMemoryStallVRAM(struct GBA* gba, int32_t wait, int extra) { UNUSED(extra); // TODO - uint16_t dispcnt = gba->memory.io[REG_DISPCNT >> 1]; + uint16_t dispcnt = gba->memory.io[GBA_REG(DISPCNT)]; int32_t stall = 0; switch (GBARegisterDISPCNTGetMode(dispcnt)) { case 2: @@ -1797,13 +1799,13 @@ int32_t GBAMemoryStallVRAM(struct GBA* gba, int32_t wait, int extra) { } void GBAMemorySerialize(const struct GBAMemory* memory, struct GBASerializedState* state) { - memcpy(state->wram, memory->wram, SIZE_WORKING_RAM); - memcpy(state->iwram, memory->iwram, SIZE_WORKING_IRAM); + memcpy(state->wram, memory->wram, GBA_SIZE_EWRAM); + memcpy(state->iwram, memory->iwram, GBA_SIZE_IWRAM); } void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedState* state) { - memcpy(memory->wram, state->wram, SIZE_WORKING_RAM); - memcpy(memory->iwram, state->iwram, SIZE_WORKING_IRAM); + memcpy(memory->wram, state->wram, GBA_SIZE_EWRAM); + memcpy(memory->iwram, state->iwram, GBA_SIZE_IWRAM); } void _pristineCow(struct GBA* gba) { @@ -1811,9 +1813,9 @@ void _pristineCow(struct GBA* gba) { return; } #if !defined(FIXED_ROM_BUFFER) && !defined(__wii__) - void* newRom = anonymousMemoryMap(SIZE_CART0); + void* newRom = anonymousMemoryMap(GBA_SIZE_ROM0); memcpy(newRom, gba->memory.rom, gba->memory.romSize); - memset(((uint8_t*) newRom) + gba->memory.romSize, 0xFF, SIZE_CART0 - gba->memory.romSize); + memset(((uint8_t*) newRom) + gba->memory.romSize, 0xFF, GBA_SIZE_ROM0 - gba->memory.romSize); if (gba->cpu->memory.activeRegion == gba->memory.rom) { gba->cpu->memory.activeRegion = newRom; } @@ -1855,16 +1857,16 @@ void GBAPrintFlush(struct GBA* gba) { static void _agbPrintStore(struct GBA* gba, uint32_t address, int16_t value) { struct GBAMemory* memory = &gba->memory; if ((address & 0x00FFFFFF) < AGB_PRINT_TOP) { - STORE_16(value, address & (SIZE_AGB_PRINT - 2), memory->agbPrintBuffer); + STORE_16(value, address & (GBA_SIZE_AGB_PRINT - 2), memory->agbPrintBuffer); } else if ((address & 0x00FFFFF8) == AGB_PRINT_STRUCT) { (&memory->agbPrintCtx.request)[(address & 7) >> 1] = value; } - if (memory->romSize == SIZE_CART0) { + if (memory->romSize == GBA_SIZE_ROM0) { _pristineCow(gba); - STORE_16(value, address & (SIZE_CART0 - 2), memory->rom); - } else if (memory->agbPrintCtx.bank == 0xFD && memory->romSize >= SIZE_CART0 / 2) { + STORE_16(value, address & (GBA_SIZE_ROM0 - 2), memory->rom); + } else if (memory->agbPrintCtx.bank == 0xFD && memory->romSize >= GBA_SIZE_ROM0 / 2) { _pristineCow(gba); - STORE_16(value, address & (SIZE_CART0 / 2 - 2), memory->rom); + STORE_16(value, address & (GBA_SIZE_ROM0 / 2 - 2), memory->rom); } } @@ -1872,7 +1874,7 @@ static int16_t _agbPrintLoad(struct GBA* gba, uint32_t address) { struct GBAMemory* memory = &gba->memory; int16_t value = address >> 1; if (address < AGB_PRINT_TOP && memory->agbPrintBuffer) { - LOAD_16(value, address & (SIZE_AGB_PRINT - 1), memory->agbPrintBuffer); + LOAD_16(value, address & (GBA_SIZE_AGB_PRINT - 1), memory->agbPrintBuffer); } else if ((address & 0x00FFFFF8) == AGB_PRINT_STRUCT) { value = (&memory->agbPrintCtx.request)[(address & 7) >> 1]; } diff --git a/src/gba/overrides.c b/src/gba/overrides.c index e15db50d8..ccc871e62 100644 --- a/src/gba/overrides.c +++ b/src/gba/overrides.c @@ -66,6 +66,9 @@ static const struct GBACartridgeOverride _overrides[] = { // F-Zero - Climax { "BFTJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, + // Goodboy Galaxy + { "2GBP", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false }, + // Iridion II { "AI2E", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, { "AI2P", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, @@ -123,10 +126,8 @@ static const struct GBACartridgeOverride _overrides[] = { { "BPEF", SAVEDATA_FLASH1M, HW_RTC, 0x80008C6, false }, // Pokemon Mystery Dungeon - { "B24J", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, { "B24E", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, { "B24P", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, - { "B24U", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, // Pokemon FireRed { "BPRJ", SAVEDATA_FLASH1M, HW_NONE, IDLE_LOOP_NONE, false }, @@ -159,6 +160,10 @@ static const struct GBACartridgeOverride _overrides[] = { // Shin Bokura no Taiyou: Gyakushuu no Sabata { "U33J", SAVEDATA_EEPROM, HW_RTC | HW_LIGHT_SENSOR, IDLE_LOOP_NONE, false }, + // Stuart Little 2 + { "ASLE", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, + { "ASLF", SAVEDATA_FORCE_NONE, HW_NONE, IDLE_LOOP_NONE, false }, + // Super Mario Advance 2 { "AA2J", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false }, { "AA2E", SAVEDATA_EEPROM, HW_NONE, 0x800052E, false }, diff --git a/src/gba/renderers/cache-set.c b/src/gba/renderers/cache-set.c index 51512721d..2f2bdef17 100644 --- a/src/gba/renderers/cache-set.c +++ b/src/gba/renderers/cache-set.c @@ -61,14 +61,14 @@ void GBAVideoCacheAssociate(struct mCacheSet* cache, struct GBAVideo* video) { mCacheSetAssignVRAM(cache, video->vram); video->renderer->cache = cache; size_t i; - for (i = 0; i < SIZE_PALETTE_RAM / 2; ++i) { + for (i = 0; i < GBA_SIZE_PALETTE_RAM / 2; ++i) { mCacheSetWritePalette(cache, i, mColorFrom555(video->palette[i])); } - GBAVideoCacheWriteVideoRegister(cache, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]); - GBAVideoCacheWriteVideoRegister(cache, REG_BG0CNT, video->p->memory.io[REG_BG0CNT >> 1]); - GBAVideoCacheWriteVideoRegister(cache, REG_BG1CNT, video->p->memory.io[REG_BG1CNT >> 1]); - GBAVideoCacheWriteVideoRegister(cache, REG_BG2CNT, video->p->memory.io[REG_BG2CNT >> 1]); - GBAVideoCacheWriteVideoRegister(cache, REG_BG3CNT, video->p->memory.io[REG_BG3CNT >> 1]); + GBAVideoCacheWriteVideoRegister(cache, GBA_REG_DISPCNT, video->p->memory.io[GBA_REG(DISPCNT)]); + GBAVideoCacheWriteVideoRegister(cache, GBA_REG_BG0CNT, video->p->memory.io[GBA_REG(BG0CNT)]); + GBAVideoCacheWriteVideoRegister(cache, GBA_REG_BG1CNT, video->p->memory.io[GBA_REG(BG1CNT)]); + GBAVideoCacheWriteVideoRegister(cache, GBA_REG_BG2CNT, video->p->memory.io[GBA_REG(BG2CNT)]); + GBAVideoCacheWriteVideoRegister(cache, GBA_REG_BG3CNT, video->p->memory.io[GBA_REG(BG3CNT)]); } static void mapParser0(struct mMapCache* cache, struct mMapCacheEntry* entry, void* vram) { @@ -195,23 +195,23 @@ static void GBAVideoCacheWriteBGCNT(struct mCacheSet* cache, size_t bg, uint16_t void GBAVideoCacheWriteVideoRegister(struct mCacheSet* cache, uint32_t address, uint16_t value) { switch (address) { - case REG_DISPCNT: + case GBA_REG_DISPCNT: GBAVideoCacheWriteDISPCNT(cache, value); GBAVideoCacheWriteBGCNT(cache, 0, (uintptr_t) mMapCacheSetGetPointer(&cache->maps, 0)->context); GBAVideoCacheWriteBGCNT(cache, 1, (uintptr_t) mMapCacheSetGetPointer(&cache->maps, 1)->context); GBAVideoCacheWriteBGCNT(cache, 2, (uintptr_t) mMapCacheSetGetPointer(&cache->maps, 2)->context); GBAVideoCacheWriteBGCNT(cache, 3, (uintptr_t) mMapCacheSetGetPointer(&cache->maps, 3)->context); break; - case REG_BG0CNT: + case GBA_REG_BG0CNT: GBAVideoCacheWriteBGCNT(cache, 0, value); break; - case REG_BG1CNT: + case GBA_REG_BG1CNT: GBAVideoCacheWriteBGCNT(cache, 1, value); break; - case REG_BG2CNT: + case GBA_REG_BG2CNT: GBAVideoCacheWriteBGCNT(cache, 2, value); break; - case REG_BG3CNT: + case GBA_REG_BG3CNT: GBAVideoCacheWriteBGCNT(cache, 3, value); break; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index b6ffa2aac..c80da2bcb 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -233,6 +233,29 @@ static const char* const _interpolate = " aff[2] = transform[start + 2].zw;\n" " mat[3] = transform[start + 3].xy;\n" " aff[3] = transform[start + 3].zw;\n" + "}\n" + + "ivec2 affineInterpolate() {\n" + " ivec2 mat[4];\n" + " ivec2 offset[4];\n" + " vec2 incoord = texCoord;\n" + " if (mosaic.x > 1) {\n" + " incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n" + " }\n" + " if (mosaic.y > 1) {\n" + " incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n" + " }\n" + " loadAffine(int(incoord.y), mat, offset);\n" + " float y = fract(incoord.y);\n" + " float start = 2. / 3.;\n" + " if (int(incoord.y) - range.x < 4) {\n" + " y = incoord.y - float(range.x);\n" + " start -= 1.;\n" + " }\n" + " float lin = start + y / 3.;\n" + " vec2 mixedTransform = interpolate(mat, lin);\n" + " vec2 mixedOffset = interpolate(offset, lin);\n" + " return ivec2(mixedTransform * incoord.x + mixedOffset);\n" "}\n"; static const char* const _renderMode2 = @@ -250,8 +273,7 @@ static const char* const _renderMode2 = "OUT(0) out vec4 color;\n" "int fetchTile(ivec2 coord);\n" - "vec2 interpolate(ivec2 arr[4], float x);\n" - "void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n" + "ivec2 affineInterpolate();\n" "int renderTile(ivec2 coord) {\n" " int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n" @@ -278,26 +300,7 @@ static const char* const _renderMode2 = "}\n" "void main() {\n" - " ivec2 mat[4];\n" - " ivec2 offset[4];\n" - " vec2 incoord = texCoord;\n" - " if (mosaic.x > 1) {\n" - " incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n" - " }\n" - " if (mosaic.y > 1) {\n" - " incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n" - " }\n" - " loadAffine(int(incoord.y), mat, offset);\n" - " float y = fract(incoord.y);\n" - " float start = 0.75;\n" - " if (int(incoord.y) - range.x < 4) {\n" - " y = incoord.y - float(range.x);\n" - " start = 0.;\n" - " }\n" - " float lin = start + y * 0.25;\n" - " vec2 mixedTransform = interpolate(mat, lin);\n" - " vec2 mixedOffset = interpolate(offset, lin);\n" - " int paletteEntry = fetchTile(ivec2(mixedTransform * incoord.x + mixedOffset));\n" + " int paletteEntry = fetchTile(affineInterpolate());\n" " color = texelFetch(palette, ivec2(paletteEntry, int(texCoord.y)), 0);\n" "}"; @@ -325,30 +328,10 @@ static const char* const _renderMode35 = "uniform ivec2 mosaic;\n" "OUT(0) out vec4 color;\n" - "vec2 interpolate(ivec2 arr[4], float x);\n" - "void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n" + "ivec2 affineInterpolate();\n" "void main() {\n" - " ivec2 mat[4];\n" - " ivec2 offset[4];\n" - " vec2 incoord = texCoord;\n" - " if (mosaic.x > 1) {\n" - " incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n" - " }\n" - " if (mosaic.y > 1) {\n" - " incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n" - " }\n" - " loadAffine(int(incoord.y), mat, offset);\n" - " float y = fract(incoord.y);\n" - " float start = 0.75;\n" - " if (int(incoord.y) - range.x < 4) {\n" - " y = incoord.y - float(range.x);\n" - " start = 0.;\n" - " }\n" - " float lin = start + y * 0.25;\n" - " vec2 mixedTransform = interpolate(mat, lin);\n" - " vec2 mixedOffset = interpolate(offset, lin);\n" - " ivec2 coord = ivec2(mixedTransform * incoord.x + mixedOffset);\n" + " ivec2 coord = affineInterpolate();\n" " if (coord.x < 0 || coord.x >= (size.x << 8)) {\n" " discard;\n" " }\n" @@ -386,30 +369,10 @@ static const char* const _renderMode4 = "uniform ivec2 mosaic;\n" "OUT(0) out vec4 color;\n" - "vec2 interpolate(ivec2 arr[4], float x);\n" - "void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n" + "ivec2 affineInterpolate();\n" "void main() {\n" - " ivec2 mat[4];\n" - " ivec2 offset[4];\n" - " vec2 incoord = texCoord;\n" - " if (mosaic.x > 1) {\n" - " incoord.x = float(MOSAIC(incoord.x, mosaic.x));\n" - " }\n" - " if (mosaic.y > 1) {\n" - " incoord.y = float(MOSAIC(incoord.y, mosaic.y));\n" - " }\n" - " loadAffine(int(incoord.y), mat, offset);\n" - " float y = fract(incoord.y);\n" - " float start = 0.75;\n" - " if (int(incoord.y) - range.x < 4) {\n" - " y = incoord.y - float(range.x);\n" - " start = 0.;\n" - " }\n" - " float lin = start + y * 0.25;\n" - " vec2 mixedTransform = interpolate(mat, lin);\n" - " vec2 mixedOffset = interpolate(offset, lin);\n" - " ivec2 coord = ivec2(mixedTransform * incoord.x + mixedOffset);\n" + " ivec2 coord = affineInterpolate();\n" " if (coord.x < 0 || coord.x >= (size.x << 8)) {\n" " discard;\n" " }\n" @@ -931,7 +894,7 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { glRenderer->nextPalette = 0; glRenderer->paletteDirtyScanlines = GBA_VIDEO_VERTICAL_PIXELS; memset(glRenderer->shadowRegs, 0, sizeof(glRenderer->shadowRegs)); - glRenderer->shadowRegs[REG_DISPCNT >> 1] = glRenderer->dispcnt; + glRenderer->shadowRegs[GBA_REG(DISPCNT)] = glRenderer->dispcnt; glRenderer->regsDirty = 0xFFFFFFFFFFFEULL; glRenderer->objOffsetX = 0; @@ -1015,107 +978,107 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, bool dirty = false; switch (address) { - case REG_DISPCNT: + case GBA_REG_DISPCNT: value &= 0xFFF7; dirty = true; break; - case REG_BG0CNT: - case REG_BG1CNT: + case GBA_REG_BG0CNT: + case GBA_REG_BG1CNT: value &= 0xDFFF; dirty = true; break; - case REG_BG0HOFS: + case GBA_REG_BG0HOFS: value &= 0x01FF; glRenderer->bg[0].x = value; break; - case REG_BG0VOFS: + case GBA_REG_BG0VOFS: value &= 0x01FF; glRenderer->bg[0].y = value; break; - case REG_BG1HOFS: + case GBA_REG_BG1HOFS: value &= 0x01FF; glRenderer->bg[1].x = value; break; - case REG_BG1VOFS: + case GBA_REG_BG1VOFS: value &= 0x01FF; glRenderer->bg[1].y = value; break; - case REG_BG2HOFS: + case GBA_REG_BG2HOFS: value &= 0x01FF; glRenderer->bg[2].x = value; break; - case REG_BG2VOFS: + case GBA_REG_BG2VOFS: value &= 0x01FF; glRenderer->bg[2].y = value; break; - case REG_BG3HOFS: + case GBA_REG_BG3HOFS: value &= 0x01FF; glRenderer->bg[3].x = value; break; - case REG_BG3VOFS: + case GBA_REG_BG3VOFS: value &= 0x01FF; glRenderer->bg[3].y = value; break; - case REG_BG2PA: + case GBA_REG_BG2PA: glRenderer->bg[2].affine.dx = value; break; - case REG_BG2PB: + case GBA_REG_BG2PB: glRenderer->bg[2].affine.dmx = value; break; - case REG_BG2PC: + case GBA_REG_BG2PC: glRenderer->bg[2].affine.dy = value; break; - case REG_BG2PD: + case GBA_REG_BG2PD: glRenderer->bg[2].affine.dmy = value; break; - case REG_BG2X_LO: + case GBA_REG_BG2X_LO: GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value); break; - case REG_BG2X_HI: + case GBA_REG_BG2X_HI: GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value); break; - case REG_BG2Y_LO: + case GBA_REG_BG2Y_LO: GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value); break; - case REG_BG2Y_HI: + case GBA_REG_BG2Y_HI: GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value); break; - case REG_BG3PA: + case GBA_REG_BG3PA: glRenderer->bg[3].affine.dx = value; break; - case REG_BG3PB: + case GBA_REG_BG3PB: glRenderer->bg[3].affine.dmx = value; break; - case REG_BG3PC: + case GBA_REG_BG3PC: glRenderer->bg[3].affine.dy = value; break; - case REG_BG3PD: + case GBA_REG_BG3PD: glRenderer->bg[3].affine.dmy = value; break; - case REG_BG3X_LO: + case GBA_REG_BG3X_LO: GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value); break; - case REG_BG3X_HI: + case GBA_REG_BG3X_HI: GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value); break; - case REG_BG3Y_LO: + case GBA_REG_BG3Y_LO: GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value); break; - case REG_BG3Y_HI: + case GBA_REG_BG3Y_HI: GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value); break; - case REG_BLDALPHA: + case GBA_REG_BLDALPHA: value &= 0x1F1F; dirty = true; break; - case REG_BLDY: + case GBA_REG_BLDY: value &= 0x1F; if (value > 0x10) { value = 0x10; } dirty = true; break; - case REG_WIN0H: + case GBA_REG_WIN0H: glRenderer->winN[0].h.end = value; glRenderer->winN[0].h.start = value >> 8; if (glRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[0].h.start > glRenderer->winN[0].h.end) { @@ -1128,7 +1091,7 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, } } break; - case REG_WIN1H: + case GBA_REG_WIN1H: glRenderer->winN[1].h.end = value; glRenderer->winN[1].h.start = value >> 8; if (glRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && glRenderer->winN[1].h.start > glRenderer->winN[1].h.end) { @@ -1141,7 +1104,7 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, } } break; - case REG_WIN0V: + case GBA_REG_WIN0V: glRenderer->winN[0].v.end = value; glRenderer->winN[0].v.start = value >> 8; if (glRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[0].v.start > glRenderer->winN[0].v.end) { @@ -1154,7 +1117,7 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, } } break; - case REG_WIN1V: + case GBA_REG_WIN1V: glRenderer->winN[1].v.end = value; glRenderer->winN[1].v.start = value >> 8; if (glRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && glRenderer->winN[1].v.start > glRenderer->winN[1].v.end) { @@ -1167,8 +1130,8 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, } } break; - case REG_WININ: - case REG_WINOUT: + case GBA_REG_WININ: + case GBA_REG_WINOUT: value &= 0x3F3F; dirty = true; break; @@ -1189,26 +1152,26 @@ uint16_t GBAVideoGLRendererWriteVideoRegister(struct GBAVideoRenderer* renderer, void _cleanRegister(struct GBAVideoGLRenderer* glRenderer, int address, uint16_t value) { switch (address) { - case REG_DISPCNT: + case GBA_REG_DISPCNT: glRenderer->dispcnt = value; GBAVideoGLRendererUpdateDISPCNT(glRenderer); break; - case REG_BG0CNT: + case GBA_REG_BG0CNT: GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[0], value); break; - case REG_BG1CNT: + case GBA_REG_BG1CNT: GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[1], value); break; - case REG_BG2CNT: + case GBA_REG_BG2CNT: GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[2], value); break; - case REG_BG3CNT: + case GBA_REG_BG3CNT: GBAVideoGLRendererWriteBGCNT(&glRenderer->bg[3], value); break; - case REG_BLDCNT: + case GBA_REG_BLDCNT: GBAVideoGLRendererWriteBLDCNT(glRenderer, value); break; - case REG_BLDALPHA: + case GBA_REG_BLDALPHA: glRenderer->blda = value & 0x1F; if (glRenderer->blda > 0x10) { glRenderer->blda = 0x10; @@ -1218,18 +1181,18 @@ void _cleanRegister(struct GBAVideoGLRenderer* glRenderer, int address, uint16_t glRenderer->bldb = 0x10; } break; - case REG_BLDY: + case GBA_REG_BLDY: glRenderer->bldy = value; break; - case REG_WININ: + case GBA_REG_WININ: glRenderer->winN[0].control = value; glRenderer->winN[1].control = value >> 8; break; - case REG_WINOUT: + case GBA_REG_WINOUT: glRenderer->winout = value; glRenderer->objwin = value >> 8; break; - case REG_MOSAIC: + case GBA_REG_MOSAIC: glRenderer->mosaic = value; break; default: diff --git a/src/gba/renderers/software-bg.c b/src/gba/renderers/software-bg.c index 8c48b41ad..7d50b5088 100644 --- a/src/gba/renderers/software-bg.c +++ b/src/gba/renderers/software-bg.c @@ -127,7 +127,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer } uint32_t current = *pixel; - if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) { + if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != background->objwinOnly) { unsigned mergedFlags = flags; if (current & FLAG_OBJWIN) { mergedFlags = objwinFlags; @@ -172,7 +172,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer if (color && IS_WRITABLE(current)) { if (!objwinSlowPath) { _compositeBlendNoObjwin(renderer, pixel, palette[color] | flags, current); - } else if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { + } else if (background->objwinForceEnable || (!(current & FLAG_OBJWIN)) == background->objwinOnly) { color_t* currentPalette = (current & FLAG_OBJWIN) ? objwinPalette : palette; unsigned mergedFlags = flags; if (current & FLAG_OBJWIN) { @@ -211,7 +211,7 @@ void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer } uint32_t current = *pixel; - if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != objwinOnly) { + if (!objwinSlowPath || (!(current & FLAG_OBJWIN)) != background->objwinOnly) { unsigned mergedFlags = flags; if (current & FLAG_OBJWIN) { mergedFlags = objwinFlags; diff --git a/src/gba/renderers/software-private.h b/src/gba/renderers/software-private.h index ec8ef4175..8a195534b 100644 --- a/src/gba/renderers/software-private.h +++ b/src/gba/renderers/software-private.h @@ -85,7 +85,7 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re } #define COMPOSITE_16_OBJWIN(BLEND, IDX) \ - if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \ + if (background->objwinForceEnable || (!(current & FLAG_OBJWIN)) == background->objwinOnly) { \ unsigned color; \ unsigned mergedFlags = flags; \ if (current & FLAG_OBJWIN) { \ @@ -111,7 +111,7 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re } #define COMPOSITE_256_OBJWIN(BLEND, IDX) \ - if (objwinForceEnable || (!(current & FLAG_OBJWIN)) == objwinOnly) { \ + if (background->objwinForceEnable || (!(current & FLAG_OBJWIN)) == background->objwinOnly) { \ unsigned color; \ unsigned mergedFlags = flags; \ if (current & FLAG_OBJWIN) { \ @@ -155,9 +155,6 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re // TODO: Remove UNUSEDs after implementing OBJWIN for modes 3 - 5 #define PREPARE_OBJWIN \ int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); \ - int objwinOnly = 0; \ - int objwinForceEnable = 0; \ - UNUSED(objwinForceEnable); \ color_t* objwinPalette = renderer->normalPalette; \ if (renderer->d.highlightAmount && background->highlight) { \ objwinPalette = renderer->highlightPalette; \ @@ -171,28 +168,6 @@ static inline void _compositeNoBlendNoObjwin(struct GBAVideoSoftwareRenderer* re palette = renderer->highlightVariantPalette; \ } \ } \ - switch (background->index) { \ - case 0: \ - objwinForceEnable = GBAWindowControlIsBg0Enable(renderer->objwin.packed) && \ - GBAWindowControlIsBg0Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg0Enable(renderer->objwin.packed); \ - break; \ - case 1: \ - objwinForceEnable = GBAWindowControlIsBg1Enable(renderer->objwin.packed) && \ - GBAWindowControlIsBg1Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg1Enable(renderer->objwin.packed); \ - break; \ - case 2: \ - objwinForceEnable = GBAWindowControlIsBg2Enable(renderer->objwin.packed) && \ - GBAWindowControlIsBg2Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg2Enable(renderer->objwin.packed); \ - break; \ - case 3: \ - objwinForceEnable = GBAWindowControlIsBg3Enable(renderer->objwin.packed) && \ - GBAWindowControlIsBg3Enable(renderer->currentWindow.packed); \ - objwinOnly = !GBAWindowControlIsBg3Enable(renderer->objwin.packed); \ - break; \ - } \ } #define BACKGROUND_BITMAP_INIT \ diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index ef82fec93..6c78c08e0 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -161,139 +161,139 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender } switch (address) { - case REG_DISPCNT: + case GBA_REG_DISPCNT: value &= 0xFFF7; softwareRenderer->dispcnt = value; GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer); break; - case REG_GREENSWP: + case GBA_REG_GREENSWP: softwareRenderer->greenswap = value & 1; break; - case REG_BG0CNT: + case GBA_REG_BG0CNT: value &= 0xDFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[0], value); break; - case REG_BG1CNT: + case GBA_REG_BG1CNT: value &= 0xDFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[1], value); break; - case REG_BG2CNT: + case GBA_REG_BG2CNT: value &= 0xFFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[2], value); break; - case REG_BG3CNT: + case GBA_REG_BG3CNT: value &= 0xFFFF; GBAVideoSoftwareRendererWriteBGCNT(softwareRenderer, &softwareRenderer->bg[3], value); break; - case REG_BG0HOFS: + case GBA_REG_BG0HOFS: value &= 0x01FF; softwareRenderer->bg[0].x = value; break; - case REG_BG0VOFS: + case GBA_REG_BG0VOFS: value &= 0x01FF; softwareRenderer->bg[0].y = value; break; - case REG_BG1HOFS: + case GBA_REG_BG1HOFS: value &= 0x01FF; softwareRenderer->bg[1].x = value; break; - case REG_BG1VOFS: + case GBA_REG_BG1VOFS: value &= 0x01FF; softwareRenderer->bg[1].y = value; break; - case REG_BG2HOFS: + case GBA_REG_BG2HOFS: value &= 0x01FF; softwareRenderer->bg[2].x = value; break; - case REG_BG2VOFS: + case GBA_REG_BG2VOFS: value &= 0x01FF; softwareRenderer->bg[2].y = value; break; - case REG_BG3HOFS: + case GBA_REG_BG3HOFS: value &= 0x01FF; softwareRenderer->bg[3].x = value; break; - case REG_BG3VOFS: + case GBA_REG_BG3VOFS: value &= 0x01FF; softwareRenderer->bg[3].y = value; break; - case REG_BG2PA: + case GBA_REG_BG2PA: softwareRenderer->bg[2].dx = value; break; - case REG_BG2PB: + case GBA_REG_BG2PB: softwareRenderer->bg[2].dmx = value; break; - case REG_BG2PC: + case GBA_REG_BG2PC: softwareRenderer->bg[2].dy = value; break; - case REG_BG2PD: + case GBA_REG_BG2PD: softwareRenderer->bg[2].dmy = value; break; - case REG_BG2X_LO: + case GBA_REG_BG2X_LO: GBAVideoSoftwareRendererWriteBGX_LO(&softwareRenderer->bg[2], value); if (softwareRenderer->bg[2].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[0][0]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG2X_HI: + case GBA_REG_BG2X_HI: GBAVideoSoftwareRendererWriteBGX_HI(&softwareRenderer->bg[2], value); if (softwareRenderer->bg[2].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[0][0]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG2Y_LO: + case GBA_REG_BG2Y_LO: GBAVideoSoftwareRendererWriteBGY_LO(&softwareRenderer->bg[2], value); if (softwareRenderer->bg[2].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[0][1]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG2Y_HI: + case GBA_REG_BG2Y_HI: GBAVideoSoftwareRendererWriteBGY_HI(&softwareRenderer->bg[2], value); if (softwareRenderer->bg[2].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[0][1]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG3PA: + case GBA_REG_BG3PA: softwareRenderer->bg[3].dx = value; break; - case REG_BG3PB: + case GBA_REG_BG3PB: softwareRenderer->bg[3].dmx = value; break; - case REG_BG3PC: + case GBA_REG_BG3PC: softwareRenderer->bg[3].dy = value; break; - case REG_BG3PD: + case GBA_REG_BG3PD: softwareRenderer->bg[3].dmy = value; break; - case REG_BG3X_LO: + case GBA_REG_BG3X_LO: GBAVideoSoftwareRendererWriteBGX_LO(&softwareRenderer->bg[3], value); if (softwareRenderer->bg[3].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[1][0]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG3X_HI: + case GBA_REG_BG3X_HI: GBAVideoSoftwareRendererWriteBGX_HI(&softwareRenderer->bg[3], value); if (softwareRenderer->bg[3].sx != softwareRenderer->cache[softwareRenderer->nextY].scale[1][0]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG3Y_LO: + case GBA_REG_BG3Y_LO: GBAVideoSoftwareRendererWriteBGY_LO(&softwareRenderer->bg[3], value); if (softwareRenderer->bg[3].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[1][1]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BG3Y_HI: + case GBA_REG_BG3Y_HI: GBAVideoSoftwareRendererWriteBGY_HI(&softwareRenderer->bg[3], value); if (softwareRenderer->bg[3].sy != softwareRenderer->cache[softwareRenderer->nextY].scale[1][1]) { DIRTY_SCANLINE(softwareRenderer, softwareRenderer->nextY); } break; - case REG_BLDCNT: + case GBA_REG_BLDCNT: GBAVideoSoftwareRendererWriteBLDCNT(softwareRenderer, value); value &= 0x3FFF; break; - case REG_BLDALPHA: + case GBA_REG_BLDALPHA: softwareRenderer->blda = value & 0x1F; if (softwareRenderer->blda > 0x10) { softwareRenderer->blda = 0x10; @@ -304,7 +304,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender } value &= 0x1F1F; break; - case REG_BLDY: + case GBA_REG_BLDY: value &= 0x1F; if (value > 0x10) { value = 0x10; @@ -314,7 +314,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender softwareRenderer->blendDirty = true; } break; - case REG_WIN0H: + case GBA_REG_WIN0H: softwareRenderer->winN[0].h.end = value; softwareRenderer->winN[0].h.start = value >> 8; if (softwareRenderer->winN[0].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && softwareRenderer->winN[0].h.start > softwareRenderer->winN[0].h.end) { @@ -327,7 +327,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender } } break; - case REG_WIN1H: + case GBA_REG_WIN1H: softwareRenderer->winN[1].h.end = value; softwareRenderer->winN[1].h.start = value >> 8; if (softwareRenderer->winN[1].h.start > GBA_VIDEO_HORIZONTAL_PIXELS && softwareRenderer->winN[1].h.start > softwareRenderer->winN[1].h.end) { @@ -340,7 +340,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender } } break; - case REG_WIN0V: + case GBA_REG_WIN0V: softwareRenderer->winN[0].v.end = value; softwareRenderer->winN[0].v.start = value >> 8; if (softwareRenderer->winN[0].v.start > GBA_VIDEO_VERTICAL_PIXELS && softwareRenderer->winN[0].v.start > softwareRenderer->winN[0].v.end) { @@ -353,7 +353,7 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender } } break; - case REG_WIN1V: + case GBA_REG_WIN1V: softwareRenderer->winN[1].v.end = value; softwareRenderer->winN[1].v.start = value >> 8; if (softwareRenderer->winN[1].v.start > GBA_VIDEO_VERTICAL_PIXELS && softwareRenderer->winN[1].v.start > softwareRenderer->winN[1].v.end) { @@ -366,17 +366,17 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender } } break; - case REG_WININ: + case GBA_REG_WININ: value &= 0x3F3F; softwareRenderer->winN[0].control.packed = value; softwareRenderer->winN[1].control.packed = value >> 8; break; - case REG_WINOUT: + case GBA_REG_WINOUT: value &= 0x3F3F; softwareRenderer->winout.packed = value; softwareRenderer->objwin.packed = value >> 8; break; - case REG_MOSAIC: + case GBA_REG_MOSAIC: softwareRenderer->mosaic = value; break; default: @@ -505,6 +505,58 @@ static void _breakWindowInner(struct GBAVideoSoftwareRenderer* softwareRenderer, #endif } +static void GBAVideoSoftwareRendererPrepareWindow(struct GBAVideoSoftwareRenderer* renderer) { + int objwinSlowPath = GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt); + if (objwinSlowPath) { + renderer->bg[0].objwinForceEnable = GBAWindowControlIsBg0Enable(renderer->objwin.packed) && + GBAWindowControlIsBg0Enable(renderer->currentWindow.packed); + renderer->bg[0].objwinOnly = !GBAWindowControlIsBg0Enable(renderer->objwin.packed); + renderer->bg[1].objwinForceEnable = GBAWindowControlIsBg1Enable(renderer->objwin.packed) && + GBAWindowControlIsBg1Enable(renderer->currentWindow.packed); + renderer->bg[1].objwinOnly = !GBAWindowControlIsBg1Enable(renderer->objwin.packed); + renderer->bg[2].objwinForceEnable = GBAWindowControlIsBg2Enable(renderer->objwin.packed) && + GBAWindowControlIsBg2Enable(renderer->currentWindow.packed); + renderer->bg[2].objwinOnly = !GBAWindowControlIsBg2Enable(renderer->objwin.packed); + renderer->bg[3].objwinForceEnable = GBAWindowControlIsBg3Enable(renderer->objwin.packed) && + GBAWindowControlIsBg3Enable(renderer->currentWindow.packed); + renderer->bg[3].objwinOnly = !GBAWindowControlIsBg3Enable(renderer->objwin.packed); + } + + switch (GBARegisterDISPCNTGetMode(renderer->dispcnt)) { + case 0: + if (renderer->bg[0].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[0]); + } + if (renderer->bg[1].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[1]); + } + // Fall through + case 2: + if (renderer->bg[3].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[3]); + } + // Fall through + case 3: + case 4: + case 5: + if (renderer->bg[2].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[2]); + } + break; + case 1: + if (renderer->bg[0].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[0]); + } + if (renderer->bg[1].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[1]); + } + if (renderer->bg[2].enabled == ENABLED_MAX) { + _updateFlags(renderer, &renderer->bg[2]); + } + break; + } +} + static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer; @@ -569,40 +621,7 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render softwareRenderer->start = softwareRenderer->end; softwareRenderer->end = softwareRenderer->windows[w].endX; softwareRenderer->currentWindow = softwareRenderer->windows[w].control; - switch (GBARegisterDISPCNTGetMode(softwareRenderer->dispcnt)) { - case 0: - if (softwareRenderer->bg[0].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[0]); - } - if (softwareRenderer->bg[1].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[1]); - } - // Fall through - case 2: - if (softwareRenderer->bg[3].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[3]); - } - // Fall through - case 3: - case 4: - case 5: - if (softwareRenderer->bg[2].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[2]); - } - break; - case 1: - if (softwareRenderer->bg[0].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[0]); - } - if (softwareRenderer->bg[1].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[1]); - } - if (softwareRenderer->bg[2].enabled == ENABLED_MAX) { - _updateFlags(softwareRenderer, &softwareRenderer->bg[2]); - } - break; - } - + GBAVideoSoftwareRendererPrepareWindow(softwareRenderer); for (priority = 0; priority < 4; ++priority) { if (spriteLayers & (1 << priority)) { GBAVideoSoftwareRendererPostprocessSprite(softwareRenderer, priority); diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 443e8015d..e7176650b 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -13,6 +13,10 @@ #include #include +#ifdef PSP2 +#include +#endif + #include #include @@ -69,22 +73,22 @@ void GBASavedataDeinit(struct GBASavedata* savedata) { } else { switch (savedata->type) { case SAVEDATA_SRAM: - mappedMemoryFree(savedata->data, SIZE_CART_SRAM); + mappedMemoryFree(savedata->data, GBA_SIZE_SRAM); break; case SAVEDATA_SRAM512: - mappedMemoryFree(savedata->data, SIZE_CART_SRAM512); + mappedMemoryFree(savedata->data, GBA_SIZE_SRAM512); break; case SAVEDATA_FLASH512: - mappedMemoryFree(savedata->data, SIZE_CART_FLASH512); + mappedMemoryFree(savedata->data, GBA_SIZE_FLASH512); break; case SAVEDATA_FLASH1M: - mappedMemoryFree(savedata->data, SIZE_CART_FLASH1M); + mappedMemoryFree(savedata->data, GBA_SIZE_FLASH1M); break; case SAVEDATA_EEPROM: - mappedMemoryFree(savedata->data, SIZE_CART_EEPROM); + mappedMemoryFree(savedata->data, GBA_SIZE_EEPROM); break; case SAVEDATA_EEPROM512: - mappedMemoryFree(savedata->data, SIZE_CART_EEPROM512); + mappedMemoryFree(savedata->data, GBA_SIZE_EEPROM512); break; case SAVEDATA_FORCE_NONE: case SAVEDATA_AUTODETECT: @@ -129,17 +133,17 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { if (savedata->data) { switch (savedata->type) { case SAVEDATA_SRAM: - return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM; + return out->write(out, savedata->data, GBA_SIZE_SRAM) == GBA_SIZE_SRAM; case SAVEDATA_SRAM512: - return out->write(out, savedata->data, SIZE_CART_SRAM512) == SIZE_CART_SRAM512; + return out->write(out, savedata->data, GBA_SIZE_SRAM512) == GBA_SIZE_SRAM512; case SAVEDATA_FLASH512: - return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512; + return out->write(out, savedata->data, GBA_SIZE_FLASH512) == GBA_SIZE_FLASH512; case SAVEDATA_FLASH1M: - return out->write(out, savedata->data, SIZE_CART_FLASH1M) == SIZE_CART_FLASH1M; + return out->write(out, savedata->data, GBA_SIZE_FLASH1M) == GBA_SIZE_FLASH1M; case SAVEDATA_EEPROM: - return out->write(out, savedata->data, SIZE_CART_EEPROM) == SIZE_CART_EEPROM; + return out->write(out, savedata->data, GBA_SIZE_EEPROM) == GBA_SIZE_EEPROM; case SAVEDATA_EEPROM512: - return out->write(out, savedata->data, SIZE_CART_EEPROM512) == SIZE_CART_EEPROM512; + return out->write(out, savedata->data, GBA_SIZE_EEPROM512) == GBA_SIZE_EEPROM512; case SAVEDATA_AUTODETECT: case SAVEDATA_FORCE_NONE: return true; @@ -160,17 +164,17 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { size_t GBASavedataSize(const struct GBASavedata* savedata) { switch (savedata->type) { case SAVEDATA_SRAM: - return SIZE_CART_SRAM; + return GBA_SIZE_SRAM; case SAVEDATA_SRAM512: - return SIZE_CART_SRAM512; + return GBA_SIZE_SRAM512; case SAVEDATA_FLASH512: - return SIZE_CART_FLASH512; + return GBA_SIZE_FLASH512; case SAVEDATA_FLASH1M: - return SIZE_CART_FLASH1M; + return GBA_SIZE_FLASH1M; case SAVEDATA_EEPROM: - return SIZE_CART_EEPROM; + return GBA_SIZE_EEPROM; case SAVEDATA_EEPROM512: - return SIZE_CART_EEPROM512; + return GBA_SIZE_EEPROM512; case SAVEDATA_FORCE_NONE: return 0; case SAVEDATA_AUTODETECT: @@ -184,7 +188,7 @@ size_t GBASavedataSize(const struct GBASavedata* savedata) { bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in) { if (savedata->data) { - if (!in && savedata->type != SAVEDATA_FORCE_NONE) { + if (!in || savedata->type == SAVEDATA_FORCE_NONE) { return false; } ssize_t size = GBASavedataSize(savedata); @@ -262,14 +266,14 @@ void GBASavedataInitFlash(struct GBASavedata* savedata) { mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } - int32_t flashSize = SIZE_CART_FLASH512; + int32_t flashSize = GBA_SIZE_FLASH512; if (savedata->type == SAVEDATA_FLASH1M) { - flashSize = SIZE_CART_FLASH1M; + flashSize = GBA_SIZE_FLASH1M; } off_t end; if (!savedata->vf) { end = 0; - savedata->data = anonymousMemoryMap(SIZE_CART_FLASH1M); + savedata->data = anonymousMemoryMap(GBA_SIZE_FLASH1M); } else { end = savedata->vf->size(savedata->vf); if (end < flashSize) { @@ -279,7 +283,7 @@ void GBASavedataInitFlash(struct GBASavedata* savedata) { } savedata->currentBank = savedata->data; - if (end < SIZE_CART_FLASH512) { + if (end < GBA_SIZE_FLASH512) { memset(&savedata->data[end], 0xFF, flashSize - end); } } @@ -291,14 +295,14 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) { mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata"); return; } - int32_t eepromSize = SIZE_CART_EEPROM512; + int32_t eepromSize = GBA_SIZE_EEPROM512; if (savedata->type == SAVEDATA_EEPROM) { - eepromSize = SIZE_CART_EEPROM; + eepromSize = GBA_SIZE_EEPROM; } off_t end; if (!savedata->vf) { end = 0; - savedata->data = anonymousMemoryMap(SIZE_CART_EEPROM); + savedata->data = anonymousMemoryMap(GBA_SIZE_EEPROM); } else { end = savedata->vf->size(savedata->vf); if (end < eepromSize) { @@ -306,8 +310,8 @@ void GBASavedataInitEEPROM(struct GBASavedata* savedata) { } savedata->data = savedata->vf->map(savedata->vf, eepromSize, savedata->mapMode); } - if (end < SIZE_CART_EEPROM512) { - memset(&savedata->data[end], 0xFF, SIZE_CART_EEPROM512 - end); + if (end < GBA_SIZE_EEPROM512) { + memset(&savedata->data[end], 0xFF, GBA_SIZE_EEPROM512 - end); } } @@ -321,17 +325,17 @@ void GBASavedataInitSRAM(struct GBASavedata* savedata) { off_t end; if (!savedata->vf) { end = 0; - savedata->data = anonymousMemoryMap(SIZE_CART_SRAM); + savedata->data = anonymousMemoryMap(GBA_SIZE_SRAM); } else { end = savedata->vf->size(savedata->vf); - if (end < SIZE_CART_SRAM) { - savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM); + if (end < GBA_SIZE_SRAM) { + savedata->vf->truncate(savedata->vf, GBA_SIZE_SRAM); } - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM, savedata->mapMode); + savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_SRAM, savedata->mapMode); } - if (end < SIZE_CART_SRAM) { - memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM - end); + if (end < GBA_SIZE_SRAM) { + memset(&savedata->data[end], 0xFF, GBA_SIZE_SRAM - end); } } @@ -345,17 +349,17 @@ void GBASavedataInitSRAM512(struct GBASavedata* savedata) { off_t end; if (!savedata->vf) { end = 0; - savedata->data = anonymousMemoryMap(SIZE_CART_SRAM512); + savedata->data = anonymousMemoryMap(GBA_SIZE_SRAM512); } else { end = savedata->vf->size(savedata->vf); - if (end < SIZE_CART_SRAM512) { - savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM512); + if (end < GBA_SIZE_SRAM512) { + savedata->vf->truncate(savedata->vf, GBA_SIZE_SRAM512); } - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM512, savedata->mapMode); + savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_SRAM512, savedata->mapMode); } - if (end < SIZE_CART_SRAM512) { - memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM512 - end); + if (end < GBA_SIZE_SRAM512) { + memset(&savedata->data[end], 0xFF, GBA_SIZE_SRAM512 - end); } } @@ -465,7 +469,7 @@ void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8 } static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) { - if (size < SIZE_CART_EEPROM512) { + if (size < GBA_SIZE_EEPROM512) { return; } if (savedata->type == SAVEDATA_EEPROM) { @@ -475,13 +479,13 @@ static void _ensureEeprom(struct GBASavedata* savedata, uint32_t size) { if (!savedata->vf) { return; } - savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_EEPROM512); - if (savedata->vf->size(savedata->vf) < SIZE_CART_EEPROM) { - savedata->vf->truncate(savedata->vf, SIZE_CART_EEPROM); - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode); - memset(&savedata->data[SIZE_CART_EEPROM512], 0xFF, SIZE_CART_EEPROM - SIZE_CART_EEPROM512); + savedata->vf->unmap(savedata->vf, savedata->data, GBA_SIZE_EEPROM512); + if (savedata->vf->size(savedata->vf) < GBA_SIZE_EEPROM) { + savedata->vf->truncate(savedata->vf, GBA_SIZE_EEPROM); + savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_EEPROM, savedata->mapMode); + memset(&savedata->data[GBA_SIZE_EEPROM512], 0xFF, GBA_SIZE_EEPROM - GBA_SIZE_EEPROM512); } else { - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_EEPROM, savedata->mapMode); + savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_EEPROM, savedata->mapMode); } } @@ -509,7 +513,7 @@ void GBASavedataWriteEEPROM(struct GBASavedata* savedata, uint16_t value, uint32 savedata->writeAddress |= (value & 0x1) << 6; } else if (writeSize == 1) { savedata->command = EEPROM_COMMAND_NULL; - } else if ((savedata->writeAddress >> 3) < SIZE_CART_EEPROM) { + } else if ((savedata->writeAddress >> 3) < GBA_SIZE_EEPROM) { _ensureEeprom(savedata, savedata->writeAddress >> 3); uint8_t current = savedata->data[savedata->writeAddress >> 3]; current &= ~(1 << (0x7 - (savedata->writeAddress & 0x7))); @@ -551,7 +555,7 @@ uint16_t GBASavedataReadEEPROM(struct GBASavedata* savedata) { int step = 63 - savedata->readBitsRemaining; uint32_t address = (savedata->readAddress + step) >> 3; _ensureEeprom(savedata, address); - if (address >= SIZE_CART_EEPROM) { + if (address >= GBA_SIZE_EEPROM) { mLOG(GBA_SAVE, GAME_ERROR, "Reading beyond end of EEPROM: %08X", address); return 0xFF; } @@ -598,14 +602,23 @@ void GBASavedataRTCWrite(struct GBASavedata* savedata) { size_t size = GBASavedataSize(savedata); savedata->vf->seek(savedata->vf, size & ~0xFF, SEEK_SET); + int bank = 0; if ((savedata->vf->size(savedata->vf) & 0xFF) != sizeof(buffer)) { // Writing past the end of the file can invalidate the file mapping + if (savedata->type == SAVEDATA_FLASH1M) { + bank = savedata->currentBank == &savedata->data[0x10000]; + } savedata->vf->unmap(savedata->vf, savedata->data, size); savedata->data = NULL; } savedata->vf->write(savedata->vf, &buffer, sizeof(buffer)); if (!savedata->data) { savedata->data = savedata->vf->map(savedata->vf, size, MAP_WRITE); + if (savedata->type == SAVEDATA_FLASH1M) { + savedata->currentBank = &savedata->data[bank << 16]; + } else if (savedata->type == SAVEDATA_FLASH512) { + savedata->currentBank = savedata->data; + } } } @@ -637,6 +650,9 @@ void GBASavedataRTCRead(struct GBASavedata* savedata) { } LOAD_64LE(savedata->gpio->rtc.lastLatch, 0, &buffer.lastLatch); + time_t rtcTime; + +#ifndef PSP2 struct tm date; date.tm_year = _unBCD(savedata->gpio->rtc.time[0]) + 100; date.tm_mon = _unBCD(savedata->gpio->rtc.time[1]) - 1; @@ -645,8 +661,40 @@ void GBASavedataRTCRead(struct GBASavedata* savedata) { date.tm_min = _unBCD(savedata->gpio->rtc.time[5]); date.tm_sec = _unBCD(savedata->gpio->rtc.time[6]); date.tm_isdst = -1; + rtcTime = mktime(&date); +#else + struct SceDateTime date; + date.year = _unBCD(savedata->gpio->rtc.time[0]) + 2000; + date.month = _unBCD(savedata->gpio->rtc.time[1]); + date.day = _unBCD(savedata->gpio->rtc.time[2]); + date.hour = _unBCD(savedata->gpio->rtc.time[4]); + date.minute = _unBCD(savedata->gpio->rtc.time[5]); + date.second = _unBCD(savedata->gpio->rtc.time[6]); + date.microsecond = 0; - savedata->gpio->rtc.offset = savedata->gpio->rtc.lastLatch - mktime(&date); + struct SceRtcTick tick; + int res; + res = sceRtcConvertDateTimeToTick(&date, &tick); + if (res < 0) { + mLOG(GBA_SAVE, ERROR, "sceRtcConvertDateTimeToTick %lx", res); + } + res = sceRtcConvertLocalTimeToUtc(&tick, &tick); + if (res < 0) { + mLOG(GBA_SAVE, ERROR, "sceRtcConvertUtcToLocalTime %lx", res); + } + res = sceRtcConvertTickToDateTime(&tick, &date); + if (res < 0) { + mLOG(GBA_SAVE, ERROR, "sceRtcConvertTickToDateTime %lx", res); + } + res = sceRtcConvertDateTimeToTime_t(&date, &rtcTime); + if (res < 0) { + mLOG(GBA_SAVE, ERROR, "sceRtcConvertDateTimeToTime_t %lx", res); + } +#endif + + savedata->gpio->rtc.offset = savedata->gpio->rtc.lastLatch - rtcTime; + + mLOG(GBA_SAVE, ERROR, "Savegame time offset set to %li", savedata->gpio->rtc.offset); } void GBASavedataSerialize(const struct GBASavedata* savedata, struct GBASerializedState* state) { @@ -699,13 +747,13 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) { mLOG(GBA_SAVE, INFO, "Updating flash chip from 512kb to 1Mb"); savedata->type = SAVEDATA_FLASH1M; if (savedata->vf) { - savedata->vf->unmap(savedata->vf, savedata->data, SIZE_CART_FLASH512); - if (savedata->vf->size(savedata->vf) < SIZE_CART_FLASH1M) { - savedata->vf->truncate(savedata->vf, SIZE_CART_FLASH1M); - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE); - memset(&savedata->data[SIZE_CART_FLASH512], 0xFF, SIZE_CART_FLASH512); + savedata->vf->unmap(savedata->vf, savedata->data, GBA_SIZE_FLASH512); + if (savedata->vf->size(savedata->vf) < GBA_SIZE_FLASH1M) { + savedata->vf->truncate(savedata->vf, GBA_SIZE_FLASH1M); + savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_FLASH1M, MAP_WRITE); + memset(&savedata->data[GBA_SIZE_FLASH512], 0xFF, GBA_SIZE_FLASH512); } else { - savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_FLASH1M, MAP_WRITE); + savedata->data = savedata->vf->map(savedata->vf, GBA_SIZE_FLASH1M, MAP_WRITE); } } } @@ -715,9 +763,9 @@ void _flashSwitchBank(struct GBASavedata* savedata, int bank) { void _flashErase(struct GBASavedata* savedata) { mLOG(GBA_SAVE, DEBUG, "Performing flash chip erase"); savedata->dirty |= mSAVEDATA_DIRT_NEW; - size_t size = SIZE_CART_FLASH512; + size_t size = GBA_SIZE_FLASH512; if (savedata->type == SAVEDATA_FLASH1M) { - size = SIZE_CART_FLASH1M; + size = GBA_SIZE_FLASH1M; } memset(savedata->data, 0xFF, size); } diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 1079932be..1669eca3d 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -62,7 +62,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) { GBASerializedMiscFlags miscFlags = 0; miscFlags = GBASerializedMiscFlagsSetHalted(miscFlags, gba->cpu->halted); - miscFlags = GBASerializedMiscFlagsSetPOSTFLG(miscFlags, gba->memory.io[REG_POSTFLG >> 1] & 1); + miscFlags = GBASerializedMiscFlagsSetPOSTFLG(miscFlags, gba->memory.io[GBA_REG(POSTFLG)] & 1); if (mTimingIsScheduled(&gba->timing, &gba->irqEvent)) { miscFlags = GBASerializedMiscFlagsFillIrqPending(miscFlags); STORE_32(gba->irqEvent.when - mTimingCurrentTime(&gba->timing), 0, &state->nextIrq); @@ -102,7 +102,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { mLOG(GBA_STATE, WARN, "Savestate created using a different version of the BIOS: expected %08X, got %08X", gba->biosChecksum, ucheck); uint32_t pc; LOAD_32(pc, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs); - if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < SIZE_BIOS && pc >= 0x20) { + if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < GBA_SIZE_BIOS && pc >= 0x20) { error = true; } } @@ -128,7 +128,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { } LOAD_32(check, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs); int region = (check >> BASE_OFFSET); - if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((check - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) { + if ((region == GBA_REGION_ROM0 || region == GBA_REGION_ROM1 || region == GBA_REGION_ROM2) && ((check - WORD_SIZE_ARM) & GBA_SIZE_ROM0) >= gba->memory.romSize - WORD_SIZE_ARM) { mLOG(GBA_STATE, WARN, "Savestate created using a differently sized version of the ROM"); error = true; } @@ -191,7 +191,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { GBASerializedMiscFlags miscFlags = 0; LOAD_32(miscFlags, 0, &state->miscFlags); gba->cpu->halted = GBASerializedMiscFlagsGetHalted(miscFlags); - gba->memory.io[REG_POSTFLG >> 1] = GBASerializedMiscFlagsGetPOSTFLG(miscFlags); + gba->memory.io[GBA_REG(POSTFLG)] = GBASerializedMiscFlagsGetPOSTFLG(miscFlags); if (GBASerializedMiscFlagsIsIrqPending(miscFlags)) { int32_t when; LOAD_32(when, 0, &state->nextIrq); diff --git a/src/gba/sharkport.c b/src/gba/sharkport.c index 9922f425f..9e1e64518 100644 --- a/src/gba/sharkport.c +++ b/src/gba/sharkport.c @@ -19,7 +19,7 @@ static bool _importSavedata(struct GBA* gba, void* payload, size_t size) { bool success = false; switch (gba->memory.savedata.type) { case SAVEDATA_FLASH512: - if (size > SIZE_CART_FLASH512) { + if (size > GBA_SIZE_FLASH512) { GBASavedataForceType(&gba->memory.savedata, SAVEDATA_FLASH1M); } // Fall through @@ -33,7 +33,7 @@ static bool _importSavedata(struct GBA* gba, void* payload, size_t size) { goto cleanup; } - if (size == SIZE_CART_EEPROM || size == SIZE_CART_EEPROM512) { + if (size == GBA_SIZE_EEPROM || size == GBA_SIZE_EEPROM512) { size_t i; for (i = 0; i < size; i += 8) { uint32_t lo, hi; @@ -119,7 +119,7 @@ int GBASavedataSharkPortPayloadSize(struct VFile* vf) { void* GBASavedataSharkPortGetPayload(struct VFile* vf, size_t* osize, uint8_t* oheader, bool testChecksum) { int32_t size = GBASavedataSharkPortPayloadSize(vf); - if (size < 0x1C || size > SIZE_CART_FLASH1M + 0x1C) { + if (size < 0x1C || size > GBA_SIZE_FLASH1M + 0x1C) { return NULL; } size -= 0x1C; @@ -336,15 +336,15 @@ int GBASavedataGSVPayloadSize(struct VFile* vf) { LOAD_32(type, 0, &header.type); switch (type) { case 2: - return SIZE_CART_SRAM; + return GBA_SIZE_SRAM; case 3: - return SIZE_CART_EEPROM512; + return GBA_SIZE_EEPROM512; case 4: - return SIZE_CART_EEPROM; + return GBA_SIZE_EEPROM; case 5: - return SIZE_CART_FLASH512; + return GBA_SIZE_FLASH512; case 6: - return SIZE_CART_FLASH1M; // Unconfirmed + return GBA_SIZE_FLASH1M; // Unconfirmed default: return vf->size(vf) - GSV_PAYLOAD_OFFSET; } @@ -352,7 +352,7 @@ int GBASavedataGSVPayloadSize(struct VFile* vf) { void* GBASavedataGSVGetPayload(struct VFile* vf, size_t* osize, uint8_t* ident, bool testChecksum) { int32_t size = GBASavedataGSVPayloadSize(vf); - if (!size || size > SIZE_CART_FLASH1M) { + if (!size || size > GBA_SIZE_FLASH1M) { return NULL; } diff --git a/src/gba/sio.c b/src/gba/sio.c index 5d418fd84..718a9f3be 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -172,7 +172,7 @@ void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) { sio->rcnt |= value & ~0xF; _switchMode(sio); if (sio->activeDriver && sio->activeDriver->writeRegister) { - sio->activeDriver->writeRegister(sio->activeDriver, REG_RCNT, value); + sio->activeDriver->writeRegister(sio->activeDriver, GBA_REG_RCNT, value); } } @@ -182,19 +182,19 @@ void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) { _switchMode(sio); } if (sio->activeDriver && sio->activeDriver->writeRegister) { - value = sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value); + value = sio->activeDriver->writeRegister(sio->activeDriver, GBA_REG_SIOCNT, value); } else { // Dummy drivers switch (sio->mode) { case SIO_NORMAL_8: case SIO_NORMAL_32: - value |= 0x0004; + value = GBASIONormalFillSi(value); if ((value & 0x0081) == 0x0081) { - if (value & 0x4000) { + if (GBASIONormalIsIrq(value)) { // TODO: Test this on hardware to see if this is correct GBARaiseIRQ(sio->p, GBA_IRQ_SIO, 0); } - value &= ~0x0080; + value = GBASIONormalClearStart(value); } break; case SIO_MULTI: @@ -217,10 +217,10 @@ uint16_t GBASIOWriteRegister(struct GBASIO* sio, uint32_t address, uint16_t valu switch (sio->mode) { case SIO_JOYBUS: switch (address) { - case REG_JOYCNT: - return (value & 0x0040) | (sio->p->memory.io[REG_JOYCNT >> 1] & ~(value & 0x7) & ~0x0040); - case REG_JOYSTAT: - return (value & 0x0030) | (sio->p->memory.io[REG_JOYSTAT >> 1] & ~0x30); + case GBA_REG_JOYCNT: + return (value & 0x0040) | (sio->p->memory.io[GBA_REG(JOYCNT)] & ~(value & 0x7) & ~0x0040); + case GBA_REG_JOYSTAT: + return (value & 0x0030) | (sio->p->memory.io[GBA_REG(JOYSTAT)] & ~0x30); } break; default: diff --git a/src/gba/sio/gbp.c b/src/gba/sio/gbp.c index 41b2f1f00..8400cc8b1 100644 --- a/src/gba/sio/gbp.c +++ b/src/gba/sio/gbp.c @@ -102,9 +102,9 @@ uint16_t _gbpRead(struct mKeyCallback* callback) { uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver; - if (address == REG_SIOCNT) { + if (address == GBA_REG_SIOCNT) { if (value & 0x0080) { - uint32_t rx = gbp->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->memory.io[REG_SIODATA32_HI >> 1] << 16); + uint32_t rx = gbp->p->memory.io[GBA_REG(SIODATA32_LO)] | (gbp->p->memory.io[GBA_REG(SIODATA32_HI)] << 16); if (gbp->txPosition < 12 && gbp->txPosition > 0) { // TODO: Check expected } else if (gbp->txPosition >= 12) { @@ -138,11 +138,11 @@ void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLat } tx = _gbpTxData[txPosition]; ++gbp->txPosition; - gbp->p->memory.io[REG_SIODATA32_LO >> 1] = tx; - gbp->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16; + gbp->p->memory.io[GBA_REG(SIODATA32_LO)] = tx; + gbp->p->memory.io[GBA_REG(SIODATA32_HI)] = tx >> 16; if (GBASIONormalIsIrq(gbp->d.p->siocnt)) { GBARaiseIRQ(gbp->p, GBA_IRQ_SIO, cyclesLate); } gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt); - gbp->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080; + gbp->p->memory.io[GBA_REG(SIOCNT)] = gbp->d.p->siocnt & ~0x0080; } diff --git a/src/gba/sio/joybus.c b/src/gba/sio/joybus.c index 3cb39b1e3..941527439 100644 --- a/src/gba/sio/joybus.c +++ b/src/gba/sio/joybus.c @@ -20,22 +20,22 @@ void GBASIOJOYCreate(struct GBASIODriver* sio) { uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint16_t value) { switch (address) { - case REG_JOYCNT: + case GBA_REG_JOYCNT: mLOG(GBA_SIO, DEBUG, "JOY write: CNT <- %04X", value); - return (value & 0x0040) | (sio->p->p->memory.io[REG_JOYCNT >> 1] & ~(value & 0x7) & ~0x0040); - case REG_JOYSTAT: + return (value & 0x0040) | (sio->p->p->memory.io[GBA_REG(JOYCNT)] & ~(value & 0x7) & ~0x0040); + case GBA_REG_JOYSTAT: mLOG(GBA_SIO, DEBUG, "JOY write: STAT <- %04X", value); - return (value & 0x0030) | (sio->p->p->memory.io[REG_JOYSTAT >> 1] & ~0x30); - case REG_JOY_TRANS_LO: + return (value & 0x0030) | (sio->p->p->memory.io[GBA_REG(JOYSTAT)] & ~0x30); + case GBA_REG_JOY_TRANS_LO: mLOG(GBA_SIO, DEBUG, "JOY write: TRANS_LO <- %04X", value); break; - case REG_JOY_TRANS_HI: + case GBA_REG_JOY_TRANS_HI: mLOG(GBA_SIO, DEBUG, "JOY write: TRANS_HI <- %04X", value); break; default: mLOG(GBA_SIO, DEBUG, "JOY write: Unknown reg %03X <- %04X", address, value); // Fall through - case REG_RCNT: + case GBA_REG_RCNT: break; } return value; @@ -44,46 +44,46 @@ uint16_t GBASIOJOYWriteRegister(struct GBASIODriver* sio, uint32_t address, uint int GBASIOJOYSendCommand(struct GBASIODriver* sio, enum GBASIOJOYCommand command, uint8_t* data) { switch (command) { case JOY_RESET: - sio->p->p->memory.io[REG_JOYCNT >> 1] |= JOYCNT_RESET; - if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { + sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_RESET; + if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) { GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0); } // Fall through case JOY_POLL: data[0] = 0x00; data[1] = 0x04; - data[2] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; + data[2] = sio->p->p->memory.io[GBA_REG(JOYSTAT)]; - mLOG(GBA_SIO, DEBUG, "JOY %s: %02X (%02X)", command == JOY_POLL ? "poll" : "reset", data[2], sio->p->p->memory.io[REG_JOYCNT >> 1]); + mLOG(GBA_SIO, DEBUG, "JOY %s: %02X (%02X)", command == JOY_POLL ? "poll" : "reset", data[2], sio->p->p->memory.io[GBA_REG(JOYCNT)]); return 3; case JOY_RECV: - sio->p->p->memory.io[REG_JOYCNT >> 1] |= JOYCNT_RECV; - sio->p->p->memory.io[REG_JOYSTAT >> 1] |= JOYSTAT_RECV; + sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_RECV; + sio->p->p->memory.io[GBA_REG(JOYSTAT)] |= JOYSTAT_RECV; - sio->p->p->memory.io[REG_JOY_RECV_LO >> 1] = data[0] | (data[1] << 8); - sio->p->p->memory.io[REG_JOY_RECV_HI >> 1] = data[2] | (data[3] << 8); + sio->p->p->memory.io[GBA_REG(JOY_RECV_LO)] = data[0] | (data[1] << 8); + sio->p->p->memory.io[GBA_REG(JOY_RECV_HI)] = data[2] | (data[3] << 8); - data[0] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; + data[0] = sio->p->p->memory.io[GBA_REG(JOYSTAT)]; - mLOG(GBA_SIO, DEBUG, "JOY recv: %02X (%02X)", data[0], sio->p->p->memory.io[REG_JOYCNT >> 1]); + mLOG(GBA_SIO, DEBUG, "JOY recv: %02X (%02X)", data[0], sio->p->p->memory.io[GBA_REG(JOYCNT)]); - if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { + if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) { GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0); } return 1; case JOY_TRANS: - data[0] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1]; - data[1] = sio->p->p->memory.io[REG_JOY_TRANS_LO >> 1] >> 8; - data[2] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1]; - data[3] = sio->p->p->memory.io[REG_JOY_TRANS_HI >> 1] >> 8; - data[4] = sio->p->p->memory.io[REG_JOYSTAT >> 1]; + data[0] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_LO)]; + data[1] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_LO)] >> 8; + data[2] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_HI)]; + data[3] = sio->p->p->memory.io[GBA_REG(JOY_TRANS_HI)] >> 8; + data[4] = sio->p->p->memory.io[GBA_REG(JOYSTAT)]; - sio->p->p->memory.io[REG_JOYCNT >> 1] |= JOYCNT_TRANS; - sio->p->p->memory.io[REG_JOYSTAT >> 1] &= ~JOYSTAT_TRANS; + sio->p->p->memory.io[GBA_REG(JOYCNT)] |= JOYCNT_TRANS; + sio->p->p->memory.io[GBA_REG(JOYSTAT)] &= ~JOYSTAT_TRANS; - mLOG(GBA_SIO, DEBUG, "JOY trans: %02X%02X%02X%02X:%02X (%02X)", data[0], data[1], data[2], data[3], data[4], sio->p->p->memory.io[REG_JOYCNT >> 1]); + mLOG(GBA_SIO, DEBUG, "JOY trans: %02X%02X%02X%02X:%02X (%02X)", data[0], data[1], data[2], data[3], data[4], sio->p->p->memory.io[GBA_REG(JOYCNT)]); - if (sio->p->p->memory.io[REG_JOYCNT >> 1] & 0x40) { + if (sio->p->p->memory.io[GBA_REG(JOYCNT)] & 0x40) { GBARaiseIRQ(sio->p->p, GBA_IRQ_SIO, 0); } return 5; diff --git a/src/gba/sio/lockstep.c b/src/gba/sio/lockstep.c index bc5a5fd33..71373a237 100644 --- a/src/gba/sio/lockstep.c +++ b/src/gba/sio/lockstep.c @@ -111,11 +111,27 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) { if (node->id) { node->d.p->rcnt |= 4; node->d.p->siocnt = GBASIOMultiplayerFillSlave(node->d.p->siocnt); + + int try; + for (try = 0; try < 3; ++try) { + uint16_t masterSiocnt; + ATOMIC_LOAD(masterSiocnt, node->p->players[0]->d.p->siocnt); + if (ATOMIC_CMPXCHG(node->p->players[0]->d.p->siocnt, masterSiocnt, GBASIOMultiplayerClearSlave(masterSiocnt))) { + break; + } + } + } else { + node->d.p->rcnt &= ~4; + node->d.p->siocnt = GBASIOMultiplayerClearSlave(node->d.p->siocnt); } break; case SIO_NORMAL_8: case SIO_NORMAL_32: - ATOMIC_ADD(node->p->attachedNormal, 1); + if (ATOMIC_ADD(node->p->attachedNormal, 1) > node->id + 1 && node->id > 0) { + node->d.p->siocnt = GBASIONormalSetSi(node->d.p->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); + } else { + node->d.p->siocnt = GBASIONormalClearSi(node->d.p->siocnt); + } node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister; break; default: @@ -176,7 +192,7 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver mLockstepLock(&node->p->d); - if (address == REG_SIOCNT) { + if (address == GBA_REG_SIOCNT) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value); enum mLockstepPhase transferActive; @@ -197,13 +213,11 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver mTimingDeschedule(&driver->p->p->timing, &node->event); } mTimingSchedule(&driver->p->p->timing, &node->event, 0); - } else { - value &= ~0x0080; } } value &= 0xFF83; value |= driver->p->siocnt & 0x00FC; - } else if (address == REG_SIOMLT_SEND) { + } else if (address == GBA_REG_SIOMLT_SEND) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOMLT_SEND <- %04X", node->id, value); } else { mLOG(GBA_SIO, STUB, "Lockstep %i: Unknown reg %03X <- %04X", node->id, address, value); @@ -222,10 +236,10 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) { struct GBASIO* sio = node->d.p; switch (node->mode) { case SIO_MULTI: - sio->p->memory.io[REG_SIOMULTI0 >> 1] = node->p->multiRecv[0]; - sio->p->memory.io[REG_SIOMULTI1 >> 1] = node->p->multiRecv[1]; - sio->p->memory.io[REG_SIOMULTI2 >> 1] = node->p->multiRecv[2]; - sio->p->memory.io[REG_SIOMULTI3 >> 1] = node->p->multiRecv[3]; + sio->p->memory.io[GBA_REG(SIOMULTI0)] = node->p->multiRecv[0]; + sio->p->memory.io[GBA_REG(SIOMULTI1)] = node->p->multiRecv[1]; + sio->p->memory.io[GBA_REG(SIOMULTI2)] = node->p->multiRecv[2]; + sio->p->memory.io[GBA_REG(SIOMULTI3)] = node->p->multiRecv[3]; sio->rcnt |= 1; sio->siocnt = GBASIOMultiplayerClearBusy(sio->siocnt); sio->siocnt = GBASIOMultiplayerSetId(sio->siocnt, node->id); @@ -238,9 +252,9 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) { sio->siocnt = GBASIONormalClearStart(sio->siocnt); if (node->id) { sio->siocnt = GBASIONormalSetSi(sio->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); - node->d.p->p->memory.io[REG_SIODATA8 >> 1] = node->p->normalRecv[node->id - 1] & 0xFF; + node->d.p->p->memory.io[GBA_REG(SIODATA8)] = node->p->normalRecv[node->id - 1] & 0xFF; } else { - node->d.p->p->memory.io[REG_SIODATA8 >> 1] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIODATA8)] = 0xFFFF; } if (GBASIONormalIsIrq(sio->siocnt)) { GBARaiseIRQ(sio->p, GBA_IRQ_SIO, 0); @@ -251,11 +265,11 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) { sio->siocnt = GBASIONormalClearStart(sio->siocnt); if (node->id) { sio->siocnt = GBASIONormalSetSi(sio->siocnt, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); - node->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = node->p->normalRecv[node->id - 1]; - node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = node->p->normalRecv[node->id - 1] >> 16; + node->d.p->p->memory.io[GBA_REG(SIODATA32_LO)] = node->p->normalRecv[node->id - 1]; + node->d.p->p->memory.io[GBA_REG(SIODATA32_HI)] = node->p->normalRecv[node->id - 1] >> 16; } else { - node->d.p->p->memory.io[REG_SIODATA32_LO >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIODATA32_LO)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIODATA32_HI)] = 0xFFFF; } if (GBASIONormalIsIrq(sio->siocnt)) { GBARaiseIRQ(sio->p, GBA_IRQ_SIO, 0); @@ -294,25 +308,25 @@ static int32_t _masterUpdate(struct GBASIOLockstepNode* node) { node->transferFinished = false; switch (node->mode) { case SIO_MULTI: - node->p->multiRecv[0] = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1]; - node->d.p->p->memory.io[REG_SIOMULTI0 >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIOMULTI2 >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIOMULTI3 >> 1] = 0xFFFF; + node->p->multiRecv[0] = node->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)]; + node->d.p->p->memory.io[GBA_REG(SIOMULTI0)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIOMULTI1)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIOMULTI2)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIOMULTI3)] = 0xFFFF; node->p->multiRecv[1] = 0xFFFF; node->p->multiRecv[2] = 0xFFFF; node->p->multiRecv[3] = 0xFFFF; break; case SIO_NORMAL_8: node->p->multiRecv[0] = 0xFFFF; - node->p->normalRecv[0] = node->d.p->p->memory.io[REG_SIODATA8 >> 1] & 0xFF; + node->p->normalRecv[0] = node->d.p->p->memory.io[GBA_REG(SIODATA8)] & 0xFF; break; case SIO_NORMAL_32: node->p->multiRecv[0] = 0xFFFF; - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]); - mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, node->d.p->p->memory.io[REG_SIODATA32_HI >> 1]); - node->p->normalRecv[0] = node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]; - node->p->normalRecv[0] |= node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] << 16; + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, node->d.p->p->memory.io[GBA_REG(SIODATA32_LO)]); + mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, node->d.p->p->memory.io[GBA_REG(SIODATA32_HI)]); + node->p->normalRecv[0] = node->d.p->p->memory.io[GBA_REG(SIODATA32_LO)]; + node->p->normalRecv[0] |= node->d.p->p->memory.io[GBA_REG(SIODATA32_HI)] << 16; break; default: node->p->multiRecv[0] = 0xFFFF; @@ -403,21 +417,21 @@ static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) { switch (node->mode) { case SIO_MULTI: node->d.p->rcnt &= ~1; - node->p->multiRecv[node->id] = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1]; - node->d.p->p->memory.io[REG_SIOMULTI0 >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIOMULTI2 >> 1] = 0xFFFF; - node->d.p->p->memory.io[REG_SIOMULTI3 >> 1] = 0xFFFF; + node->p->multiRecv[node->id] = node->d.p->p->memory.io[GBA_REG(SIOMLT_SEND)]; + node->d.p->p->memory.io[GBA_REG(SIOMULTI0)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIOMULTI1)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIOMULTI2)] = 0xFFFF; + node->d.p->p->memory.io[GBA_REG(SIOMULTI3)] = 0xFFFF; node->d.p->siocnt = GBASIOMultiplayerFillBusy(node->d.p->siocnt); break; case SIO_NORMAL_8: node->p->multiRecv[node->id] = 0xFFFF; - node->p->normalRecv[node->id] = node->d.p->p->memory.io[REG_SIODATA8 >> 1] & 0xFF; + node->p->normalRecv[node->id] = node->d.p->p->memory.io[GBA_REG(SIODATA8)] & 0xFF; break; case SIO_NORMAL_32: node->p->multiRecv[node->id] = 0xFFFF; - node->p->normalRecv[node->id] = node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]; - node->p->normalRecv[node->id] |= node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] << 16; + node->p->normalRecv[node->id] = node->d.p->p->memory.io[GBA_REG(SIODATA32_LO)]; + node->p->normalRecv[node->id] |= node->d.p->p->memory.io[GBA_REG(SIODATA32_HI)] << 16; break; default: node->p->multiRecv[node->id] = 0xFFFF; @@ -447,7 +461,7 @@ static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user, struct GBASIOLockstepNode* node = user; mLockstepLock(&node->p->d); - int32_t cycles = cycles = node->nextEvent; + int32_t cycles = node->nextEvent; node->nextEvent -= cyclesLate; node->eventDiff += cyclesLate; if (node->p->d.attached < 2) { @@ -493,13 +507,30 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive mLockstepLock(&node->p->d); - if (address == REG_SIOCNT) { + if (address == GBA_REG_SIOCNT) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value); + int attached; + ATOMIC_LOAD(attached, node->p->attachedNormal); value &= 0xFF8B; - if (!node->id) { + if (node->id > 0) { + value = GBASIONormalSetSi(value, GBASIONormalGetIdleSo(node->p->players[node->id - 1]->d.p->siocnt)); + } else { value = GBASIONormalClearSi(value); } - if (value & 0x0080) { + + enum mLockstepPhase transferActive; + ATOMIC_LOAD(transferActive, node->p->d.transferActive); + if (node->id < 3 && attached > node->id + 1 && transferActive == TRANSFER_IDLE) { + int try; + for (try = 0; try < 3; ++try) { + GBASIONormal nextSiocnct; + ATOMIC_LOAD(nextSiocnct, node->p->players[node->id + 1]->d.p->siocnt); + if (ATOMIC_CMPXCHG(node->p->players[node->id + 1]->d.p->siocnt, nextSiocnct, GBASIONormalSetSi(nextSiocnct, GBASIONormalGetIdleSo(value)))) { + break; + } + } + } + if ((value & 0x0081) == 0x0081) { if (!node->id) { // Frequency int32_t cycles; @@ -512,9 +543,6 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive cycles *= 4; } - enum mLockstepPhase transferActive; - ATOMIC_LOAD(transferActive, node->p->d.transferActive); - if (transferActive == TRANSFER_IDLE) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id); ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING); @@ -529,14 +557,14 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive value &= ~0x0080; } } else { - + // TODO } } - } else if (address == REG_SIODATA32_LO) { + } else if (address == GBA_REG_SIODATA32_LO) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, value); - } else if (address == REG_SIODATA32_HI) { + } else if (address == GBA_REG_SIODATA32_HI) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, value); - } else if (address == REG_SIODATA8) { + } else if (address == GBA_REG_SIODATA8) { mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA8 <- %02X", node->id, value); } diff --git a/src/gba/timer.c b/src/gba/timer.c index 8a3a3e8f6..e0debb111 100644 --- a/src/gba/timer.c +++ b/src/gba/timer.c @@ -8,12 +8,12 @@ #include #include -#define REG_TMCNT_LO(X) (REG_TM0CNT_LO + ((X) << 2)) +#define GBA_REG_TMCNT_LO(X) (GBA_REG_TM0CNT_LO + ((X) << 2)) static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) { struct GBATimer* timer = &gba->timers[timerId]; if (GBATimerFlagsIsCountUp(timer->flags)) { - gba->memory.io[REG_TMCNT_LO(timerId) >> 1] = timer->reload; + gba->memory.io[GBA_REG_TMCNT_LO(timerId) >> 1] = timer->reload; } else { GBATimerUpdateRegister(gba, timerId, cyclesLate); } @@ -34,9 +34,9 @@ static void GBATimerUpdate(struct GBA* gba, int timerId, uint32_t cyclesLate) { if (timerId < 3) { struct GBATimer* nextTimer = &gba->timers[timerId + 1]; - if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled? - ++gba->memory.io[REG_TMCNT_LO(timerId + 1) >> 1]; - if (!gba->memory.io[REG_TMCNT_LO(timerId + 1) >> 1] && GBATimerFlagsIsEnable(nextTimer->flags)) { + if (GBATimerFlagsIsCountUp(nextTimer->flags) && GBATimerFlagsIsEnable(nextTimer->flags)) { + ++gba->memory.io[GBA_REG_TMCNT_LO(timerId + 1) >> 1]; + if (!gba->memory.io[GBA_REG_TMCNT_LO(timerId + 1) >> 1] && GBATimerFlagsIsEnable(nextTimer->flags)) { GBATimerUpdate(gba, timerId + 1, cyclesLate); } } @@ -99,11 +99,11 @@ void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate) { int32_t tickIncrement = currentTime - currentTimer->lastEvent; currentTimer->lastEvent = currentTime; tickIncrement >>= prescaleBits; - tickIncrement += gba->memory.io[REG_TMCNT_LO(timer) >> 1]; + tickIncrement += gba->memory.io[GBA_REG_TMCNT_LO(timer) >> 1]; while (tickIncrement >= 0x10000) { tickIncrement -= 0x10000 - currentTimer->reload; } - gba->memory.io[REG_TMCNT_LO(timer) >> 1] = tickIncrement; + gba->memory.io[GBA_REG_TMCNT_LO(timer) >> 1] = tickIncrement; // Schedule next update tickIncrement = (0x10000 - tickIncrement) << prescaleBits; @@ -134,7 +134,7 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { if (GBATimerFlagsIsEnable(oldFlags) != GBATimerFlagsIsEnable(currentTimer->flags)) { reschedule = true; if (GBATimerFlagsIsEnable(currentTimer->flags)) { - gba->memory.io[REG_TMCNT_LO(timer) >> 1] = currentTimer->reload; + gba->memory.io[GBA_REG_TMCNT_LO(timer) >> 1] = currentTimer->reload; } } else if (GBATimerFlagsIsCountUp(oldFlags) != GBATimerFlagsIsCountUp(currentTimer->flags)) { reschedule = true; diff --git a/src/gba/video.c b/src/gba/video.c index 7268f19de..bfe556943 100644 --- a/src/gba/video.c +++ b/src/gba/video.c @@ -54,7 +54,7 @@ MGBA_EXPORT const int GBAVideoObjSizes[16][2] = { void GBAVideoInit(struct GBAVideo* video) { video->renderer = NULL; - video->vram = anonymousMemoryMap(SIZE_VRAM); + video->vram = anonymousMemoryMap(GBA_SIZE_VRAM); video->frameskip = 0; video->event.name = "GBA Video"; video->event.callback = NULL; @@ -71,7 +71,7 @@ void GBAVideoReset(struct GBAVideo* video) { video->vcount = 0x7E; nextEvent = 117; } - video->p->memory.io[REG_VCOUNT >> 1] = video->vcount; + video->p->memory.io[GBA_REG(VCOUNT)] = video->vcount; video->event.callback = _startHblank; mTimingSchedule(&video->p->timing, &video->event, nextEvent); @@ -93,7 +93,7 @@ void GBAVideoReset(struct GBAVideo* video) { void GBAVideoDeinit(struct GBAVideo* video) { video->renderer->deinit(video->renderer); - mappedMemoryFree(video->vram, SIZE_VRAM); + mappedMemoryFree(video->vram, GBA_SIZE_VRAM); } void GBAVideoDummyRendererCreate(struct GBAVideoRenderer* renderer) { @@ -126,10 +126,10 @@ void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer* renderer->oam = &video->oam; video->renderer->init(video->renderer); video->renderer->reset(video->renderer); - renderer->writeVideoRegister(renderer, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]); - renderer->writeVideoRegister(renderer, REG_GREENSWP, video->p->memory.io[REG_GREENSWP >> 1]); + renderer->writeVideoRegister(renderer, GBA_REG_DISPCNT, video->p->memory.io[GBA_REG(DISPCNT)]); + renderer->writeVideoRegister(renderer, GBA_REG_GREENSWP, video->p->memory.io[GBA_REG(GREENSWP)]); int address; - for (address = REG_BG0CNT; address < 0x56; address += 2) { + for (address = GBA_REG_BG0CNT; address < 0x56; address += 2) { if (address == 0x4E) { continue; } @@ -146,13 +146,13 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { if (video->vcount == VIDEO_VERTICAL_TOTAL_PIXELS) { video->vcount = 0; } - video->p->memory.io[REG_VCOUNT >> 1] = video->vcount; + video->p->memory.io[GBA_REG(VCOUNT)] = video->vcount; if (video->vcount < GBA_VIDEO_VERTICAL_PIXELS) { video->shouldStall = 1; } - GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; + GBARegisterDISPSTAT dispstat = video->p->memory.io[GBA_REG(DISPSTAT)]; dispstat = GBARegisterDISPSTATClearInHblank(dispstat); if (video->vcount == GBARegisterDISPSTATGetVcountSetting(dispstat)) { dispstat = GBARegisterDISPSTATFillVcounter(dispstat); @@ -162,7 +162,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { } else { dispstat = GBARegisterDISPSTATClearVcounter(dispstat); } - video->p->memory.io[REG_DISPSTAT >> 1] = dispstat; + video->p->memory.io[GBA_REG(DISPSTAT)] = dispstat; // Note: state may be recorded during callbacks, so ensure it is consistent! switch (video->vcount) { @@ -170,7 +170,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { GBAFrameStarted(video->p); break; case GBA_VIDEO_VERTICAL_PIXELS: - video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATFillInVblank(dispstat); + video->p->memory.io[GBA_REG(DISPSTAT)] = GBARegisterDISPSTATFillInVblank(dispstat); if (video->frameskipCounter <= 0) { video->renderer->finishFrame(video->renderer); } @@ -188,7 +188,7 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) { video->p->earlyExit = true; break; case VIDEO_VERTICAL_TOTAL_PIXELS - 1: - video->p->memory.io[REG_DISPSTAT >> 1] = GBARegisterDISPSTATClearInVblank(dispstat); + video->p->memory.io[GBA_REG(DISPSTAT)] = GBARegisterDISPSTATClearInVblank(dispstat); break; } } @@ -199,7 +199,7 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) { mTimingSchedule(timing, &video->event, VIDEO_HBLANK_LENGTH - cyclesLate); // Begin Hblank - GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1]; + GBARegisterDISPSTAT dispstat = video->p->memory.io[GBA_REG(DISPSTAT)]; dispstat = GBARegisterDISPSTATFillInHblank(dispstat); if (video->vcount < GBA_VIDEO_VERTICAL_PIXELS && video->frameskipCounter <= 0) { video->renderer->drawScanline(video->renderer, video->vcount); @@ -215,12 +215,12 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) { GBARaiseIRQ(video->p, GBA_IRQ_HBLANK, cyclesLate - 6); // TODO: Where does this fudge factor come from? } video->shouldStall = 0; - video->p->memory.io[REG_DISPSTAT >> 1] = dispstat; + video->p->memory.io[GBA_REG(DISPSTAT)] = dispstat; } void GBAVideoWriteDISPSTAT(struct GBAVideo* video, uint16_t value) { - video->p->memory.io[REG_DISPSTAT >> 1] &= 0x7; - video->p->memory.io[REG_DISPSTAT >> 1] |= value; + video->p->memory.io[GBA_REG(DISPSTAT)] &= 0x7; + video->p->memory.io[GBA_REG(DISPSTAT)] |= value; // TODO: Does a VCounter IRQ trigger on write? } @@ -244,35 +244,35 @@ static uint16_t GBAVideoDummyRendererWriteVideoRegister(struct GBAVideoRenderer* GBAVideoCacheWriteVideoRegister(renderer->cache, address, value); } switch (address) { - case REG_DISPCNT: + case GBA_REG_DISPCNT: value &= 0xFFF7; break; - case REG_BG0CNT: - case REG_BG1CNT: + case GBA_REG_BG0CNT: + case GBA_REG_BG1CNT: value &= 0xDFFF; break; - case REG_BG2CNT: - case REG_BG3CNT: + case GBA_REG_BG2CNT: + case GBA_REG_BG3CNT: value &= 0xFFFF; break; - case REG_BG0HOFS: - case REG_BG0VOFS: - case REG_BG1HOFS: - case REG_BG1VOFS: - case REG_BG2HOFS: - case REG_BG2VOFS: - case REG_BG3HOFS: - case REG_BG3VOFS: + case GBA_REG_BG0HOFS: + case GBA_REG_BG0VOFS: + case GBA_REG_BG1HOFS: + case GBA_REG_BG1VOFS: + case GBA_REG_BG2HOFS: + case GBA_REG_BG2VOFS: + case GBA_REG_BG3HOFS: + case GBA_REG_BG3VOFS: value &= 0x01FF; break; - case REG_BLDCNT: + case GBA_REG_BLDCNT: value &= 0x3FFF; break; - case REG_BLDALPHA: + case GBA_REG_BLDALPHA: value &= 0x1F1F; break; - case REG_WININ: - case REG_WINOUT: + case GBA_REG_WININ: + case GBA_REG_WINOUT: value &= 0x3F3F; break; default: @@ -325,9 +325,9 @@ static void GBAVideoDummyRendererPutPixels(struct GBAVideoRenderer* renderer, si } void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* state) { - memcpy(state->vram, video->vram, SIZE_VRAM); - memcpy(state->oam, video->oam.raw, SIZE_OAM); - memcpy(state->pram, video->palette, SIZE_PALETTE_RAM); + memcpy(state->vram, video->vram, GBA_SIZE_VRAM); + memcpy(state->oam, video->oam.raw, GBA_SIZE_OAM); + memcpy(state->pram, video->palette, GBA_SIZE_PALETTE_RAM); STORE_32(video->event.when - mTimingCurrentTime(&video->p->timing), 0, &state->video.nextEvent); int32_t flags = 0; if (video->event.callback == _startHdraw) { @@ -340,23 +340,23 @@ void GBAVideoSerialize(const struct GBAVideo* video, struct GBASerializedState* } void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState* state) { - memcpy(video->vram, state->vram, SIZE_VRAM); + memcpy(video->vram, state->vram, GBA_SIZE_VRAM); uint16_t value; int i; - for (i = 0; i < SIZE_OAM; i += 2) { + for (i = 0; i < GBA_SIZE_OAM; i += 2) { LOAD_16(value, i, state->oam); - GBAStore16(video->p->cpu, BASE_OAM | i, value, 0); + GBAStore16(video->p->cpu, GBA_BASE_OAM | i, value, 0); } - for (i = 0; i < SIZE_PALETTE_RAM; i += 2) { + for (i = 0; i < GBA_SIZE_PALETTE_RAM; i += 2) { LOAD_16(value, i, state->pram); - GBAStore16(video->p->cpu, BASE_PALETTE_RAM | i, value, 0); + GBAStore16(video->p->cpu, GBA_BASE_PALETTE_RAM | i, value, 0); } LOAD_32(video->frameCounter, 0, &state->video.frameCounter); video->shouldStall = 0; int32_t flags; LOAD_32(flags, 0, &state->video.flags); - GBARegisterDISPSTAT dispstat = state->io[REG_DISPSTAT >> 1]; + GBARegisterDISPSTAT dispstat = state->io[GBA_REG(DISPSTAT)]; switch (GBASerializedVideoFlagsGetMode(flags)) { case 0: if (GBARegisterDISPSTATIsInHblank(dispstat)) { @@ -385,6 +385,6 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState } mTimingSchedule(&video->p->timing, &video->event, when); - LOAD_16(video->vcount, REG_VCOUNT, state->io); + LOAD_16(video->vcount, GBA_REG_VCOUNT, state->io); video->renderer->reset(video->renderer); } diff --git a/src/platform/3ds/3ds-memory.c b/src/platform/3ds/3ds-memory.c deleted file mode 100644 index c37e4637b..000000000 --- a/src/platform/3ds/3ds-memory.c +++ /dev/null @@ -1,17 +0,0 @@ -/* Copyright (c) 2013-2014 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 - -#include <3ds.h> - -void* anonymousMemoryMap(size_t size) { - return linearAlloc(size); -} - -void mappedMemoryFree(void* memory, size_t size) { - UNUSED(size); - linearFree(memory); -} diff --git a/src/platform/3ds/CMakeLists.txt b/src/platform/3ds/CMakeLists.txt index 893af0317..ef70eed51 100644 --- a/src/platform/3ds/CMakeLists.txt +++ b/src/platform/3ds/CMakeLists.txt @@ -19,15 +19,19 @@ if(${CMAKE_BUILD_TYPE} STREQUAL Debug OR ${CMAKE_BUILD_TYPE} STREQUAL RelWithDeb else() list(APPEND OS_LIB citro3d ctru) endif() -file(GLOB OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/3ds-*.c ${CMAKE_CURRENT_SOURCE_DIR}/ctru-heap.c ${CMAKE_CURRENT_SOURCE_DIR}/socket.c) -set(OS_SRC ${OS_SRC} PARENT_SCOPE) +set(OS_SRC + ${PROJECT_SOURCE_DIR}/src/util/memory.c + ${CMAKE_CURRENT_SOURCE_DIR}/3ds-vfs.c + ${CMAKE_CURRENT_SOURCE_DIR}/ctru-heap.c + ${CMAKE_CURRENT_SOURCE_DIR}/socket.c + PARENT_SCOPE) set(OS_LIB ${OS_LIB} PARENT_SCOPE) source_group("3DS-specific code" FILES ${OS_SRC}) if(USE_VFS_3DS) list(APPEND OS_DEFINES USE_VFS_3DS) else() - list(APPEND CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) + list(APPEND CORE_VFS_SRC ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) endif() set(CORE_VFS_SRC ${CORE_VFS_SRC} PARENT_SCOPE) set(OS_DEFINES ${OS_DEFINES} PARENT_SCOPE) @@ -54,8 +58,8 @@ set_target_properties(${BINARY_NAME}.elf PROPERTIES COMPILE_DEFINITIONS "${OS_DE target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${M_LIBRARY} ${OS_LIB}) add_custom_command(OUTPUT ${BINARY_NAME}.smdh - COMMAND ${BANNERTOOL} makesmdh -s "${PROJECT_NAME}" -l "${SUMMARY}" -p "endrift" -i ${CMAKE_SOURCE_DIR}/res/mgba-48.png -o ${BINARY_NAME}.smdh - DEPENDS ${CMAKE_SOURCE_DIR}/res/mgba-48.png) + COMMAND ${BANNERTOOL} makesmdh -s "${PROJECT_NAME}" -l "${SUMMARY}" -p "endrift" -i ${PROJECT_SOURCE_DIR}/res/mgba-48.png -o ${BINARY_NAME}.smdh + DEPENDS ${PROJECT_SOURCE_DIR}/res/mgba-48.png) add_custom_command(OUTPUT ${BINARY_NAME}.xml COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/hbl.xml ${BINARY_NAME}.xml @@ -67,8 +71,8 @@ add_custom_command(OUTPUT ${BINARY_NAME}.bnr # tex3ds binaries as of 2.0.1-3 crash if you try to do this #add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.t3x -# COMMAND ${TEX3DS} -f rgb5551 -o icons.t3x ${CMAKE_SOURCE_DIR}/res/icons.png -# MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/res/icons.png +# COMMAND ${TEX3DS} -f rgb5551 -o icons.t3x ${PROJECT_SOURCE_DIR}/res/icons.png +# MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/res/icons.png # WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c diff --git a/src/platform/3ds/ctru-heap.c b/src/platform/3ds/ctru-heap.c index 25e606c1d..ea2f4d450 100644 --- a/src/platform/3ds/ctru-heap.c +++ b/src/platform/3ds/ctru-heap.c @@ -7,9 +7,6 @@ #include -u32 __ctru_heap_size = 0x02400000; -u32 __ctru_linear_heap_size = 0x01400000; - uint32_t* romBuffer = NULL; size_t romBufferSize; diff --git a/src/platform/3ds/gui-font.c b/src/platform/3ds/gui-font.c index 668c7382d..c9846c628 100644 --- a/src/platform/3ds/gui-font.c +++ b/src/platform/3ds/gui-font.c @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include -#include +#include #include #include "icons.h" diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 5356130ce..470c50db7 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -496,7 +496,7 @@ static void _drawTex(struct mCore* core, bool faded, bool both) { int wide = isWide ? 2 : 1; unsigned corew, coreh; - core->desiredVideoDimensions(core, &corew, &coreh); + core->currentVideoSize(core, &corew, &coreh); int w = corew; int h = coreh; @@ -872,7 +872,7 @@ int main(int argc, char* argv[]) { u8 model = 0; cfguInit(); CFGU_GetSystemModel(&model); - if (model != 3 /* o2DS */) { + if (model != CFG_MODEL_2DS) { gfxSetWide(true); } cfguExit(); diff --git a/src/platform/example/client-server/server.c b/src/platform/example/client-server/server.c index ba0347b69..0dcec9b15 100644 --- a/src/platform/example/client-server/server.c +++ b/src/platform/example/client-server/server.c @@ -83,7 +83,7 @@ bool _mExampleRun(const struct mArguments* args, Socket client) { // Get the dimensions required for this core and send them to the client. unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->baseVideoSize(core, &width, &height); ssize_t bufferSize = width * height * BYTES_PER_PIXEL; uint32_t sendNO; sendNO = htonl(width); diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 3f0b49bd7..8350ad639 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -1266,7 +1266,7 @@ static void _doDeferredSetup(void) { // On the off-hand chance that a core actually expects its buffers to be populated when // you actually first get them, you're out of luck without workarounds. Yup, seriously. // Here's that workaround, but really the API needs to be thrown out and rewritten. - struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); + struct VFile* save = VFileFromMemory(savedata, GBA_SIZE_FLASH1M); if (!core->loadSave(core, save)) { save->close(save); } @@ -1339,19 +1339,13 @@ void retro_get_system_info(struct retro_system_info* info) { void retro_get_system_av_info(struct retro_system_av_info* info) { unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); info->geometry.base_width = width; info->geometry.base_height = height; -#ifdef M_CORE_GB - if (core->platform(core) == mPLATFORM_GB) { - info->geometry.max_width = VIDEO_WIDTH_MAX; - info->geometry.max_height = VIDEO_HEIGHT_MAX; - } else -#endif - { - info->geometry.max_width = width; - info->geometry.max_height = height; - } + + core->baseVideoSize(core, &width, &height); + info->geometry.max_width = width; + info->geometry.max_height = height; info->geometry.aspect_ratio = width / (double) height; info->timing.fps = core->frequency(core) / (float) core->frameCycles(core); @@ -1661,7 +1655,7 @@ void retro_run(void) { core->runFrame(core); unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); /* If using 'Fixed Interval' frameskipping, check * whether a frame is currently available */ @@ -1753,66 +1747,66 @@ static void _setupMaps(struct mCore* core) { /* Map internal working RAM */ descs[0].ptr = gba->memory.iwram; - descs[0].start = BASE_WORKING_IRAM; - descs[0].len = SIZE_WORKING_IRAM; + descs[0].start = GBA_BASE_IWRAM; + descs[0].len = GBA_SIZE_IWRAM; descs[0].select = 0xFF000000; /* Map working RAM */ descs[1].ptr = gba->memory.wram; - descs[1].start = BASE_WORKING_RAM; - descs[1].len = SIZE_WORKING_RAM; + descs[1].start = GBA_BASE_EWRAM; + descs[1].len = GBA_SIZE_EWRAM; descs[1].select = 0xFF000000; /* Map save RAM */ /* TODO: if SRAM is flash, use start=0 addrspace="S" instead */ descs[2].ptr = savedataSize ? savedata : NULL; - descs[2].start = BASE_CART_SRAM; + descs[2].start = GBA_BASE_SRAM; descs[2].len = savedataSize; /* Map ROM */ descs[3].ptr = gba->memory.rom; - descs[3].start = BASE_CART0; + descs[3].start = GBA_BASE_ROM0; descs[3].len = romSize; descs[3].flags = RETRO_MEMDESC_CONST; descs[4].ptr = gba->memory.rom; - descs[4].start = BASE_CART1; + descs[4].start = GBA_BASE_ROM1; descs[4].len = romSize; descs[4].flags = RETRO_MEMDESC_CONST; descs[5].ptr = gba->memory.rom; - descs[5].start = BASE_CART2; + descs[5].start = GBA_BASE_ROM2; descs[5].len = romSize; descs[5].flags = RETRO_MEMDESC_CONST; /* Map BIOS */ descs[6].ptr = gba->memory.bios; - descs[6].start = BASE_BIOS; - descs[6].len = SIZE_BIOS; + descs[6].start = GBA_BASE_BIOS; + descs[6].len = GBA_SIZE_BIOS; descs[6].flags = RETRO_MEMDESC_CONST; /* Map VRAM */ descs[7].ptr = gba->video.vram; - descs[7].start = BASE_VRAM; - descs[7].len = SIZE_VRAM; + descs[7].start = GBA_BASE_VRAM; + descs[7].len = GBA_SIZE_VRAM; descs[7].select = 0xFF000000; /* Map palette RAM */ descs[8].ptr = gba->video.palette; - descs[8].start = BASE_PALETTE_RAM; - descs[8].len = SIZE_PALETTE_RAM; + descs[8].start = GBA_BASE_PALETTE_RAM; + descs[8].len = GBA_SIZE_PALETTE_RAM; descs[8].select = 0xFF000000; /* Map OAM */ descs[9].ptr = &gba->video.oam; /* video.oam is a structure */ - descs[9].start = BASE_OAM; - descs[9].len = SIZE_OAM; + descs[9].start = GBA_BASE_OAM; + descs[9].len = GBA_SIZE_OAM; descs[9].select = 0xFF000000; /* Map mmapped I/O */ descs[10].ptr = gba->memory.io; - descs[10].start = BASE_IO; - descs[10].len = SIZE_IO; + descs[10].start = GBA_BASE_IO; + descs[10].len = GBA_SIZE_IO; mmaps.descriptors = descs; mmaps.num_descriptors = sizeof(descs) / sizeof(descs[0]); @@ -2058,8 +2052,8 @@ bool retro_load_game(const struct retro_game_info* game) { core->setPeripheral(core, mPERIPH_RUMBLE, &rumble); core->setPeripheral(core, mPERIPH_ROTATION, &rotation); - savedata = anonymousMemoryMap(SIZE_CART_FLASH1M); - memset(savedata, 0xFF, SIZE_CART_FLASH1M); + savedata = anonymousMemoryMap(GBA_SIZE_FLASH1M); + memset(savedata, 0xFF, GBA_SIZE_FLASH1M); _reloadSettings(); core->loadROM(core, rom); @@ -2139,7 +2133,7 @@ void retro_unload_game(void) { core->deinit(core); mappedMemoryFree(data, dataSize); data = 0; - mappedMemoryFree(savedata, SIZE_CART_FLASH1M); + mappedMemoryFree(savedata, GBA_SIZE_FLASH1M); savedata = 0; } @@ -2322,7 +2316,7 @@ size_t retro_get_memory_size(unsigned id) { case mPLATFORM_GBA: switch (((struct GBA*) core->board)->memory.savedata.type) { case SAVEDATA_AUTODETECT: - return SIZE_CART_FLASH1M; + return GBA_SIZE_FLASH1M; default: return GBASavedataSize(&((struct GBA*) core->board)->memory.savedata); } @@ -2525,7 +2519,7 @@ static void _startImage(struct mImageSource* image, unsigned w, unsigned h, int static void _stopImage(struct mImageSource* image) { UNUSED(image); - cam.stop(); + cam.stop(); } static void _requestImage(struct mImageSource* image, const void** buffer, size_t* stride, enum mColorFormat* colorFormat) { diff --git a/src/platform/openemu/mGBAGameCore.m b/src/platform/openemu/mGBAGameCore.m index 36bb3464a..7656a8945 100644 --- a/src/platform/openemu/mGBAGameCore.m +++ b/src/platform/openemu/mGBAGameCore.m @@ -68,7 +68,7 @@ outputBuffer = nil; unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->baseVideoSize(core, &width, &height); outputBuffer = malloc(width * height * BYTES_PER_PIXEL); core->setVideoBuffer(core, outputBuffer, width); core->setAudioBufferSize(core, SAMPLES); @@ -143,14 +143,14 @@ - (OEIntRect)screenRect { unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->currentVideoSize(core, &width, &height); return OEIntRectMake(0, 0, width, height); } - (OEIntSize)bufferSize { unsigned width, height; - core->desiredVideoDimensions(core, &width, &height); + core->baseVideoSize(core, &width, &height); return OEIntSizeMake(width, height); } diff --git a/src/platform/opengl/gl.c b/src/platform/opengl/gl.c index 76089c4c0..fe24d04cf 100644 --- a/src/platform/opengl/gl.c +++ b/src/platform/opengl/gl.c @@ -9,9 +9,9 @@ static const GLint _glVertices[] = { 0, 0, - 256, 0, - 256, 256, - 0, 256 + 1, 0, + 1, 1, + 0, 1 }; static const GLint _glTexCoords[] = { @@ -21,76 +21,102 @@ static const GLint _glTexCoords[] = { 0, 1 }; +static inline void _initTex(void) { + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#ifndef _WIN32 + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#endif +} + static void mGLContextInit(struct VideoBackend* v, WHandle handle) { UNUSED(handle); struct mGLContext* context = (struct mGLContext*) v; - v->width = 1; - v->height = 1; + memset(context->layerDims, 0, sizeof(context->layerDims)); + memset(context->imageSizes, -1, sizeof(context->imageSizes)); glGenTextures(2, context->tex); glBindTexture(GL_TEXTURE_2D, context->tex[0]); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -#ifndef _WIN32 - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -#endif + _initTex(); glBindTexture(GL_TEXTURE_2D, context->tex[1]); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -#ifndef _WIN32 - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -#endif + _initTex(); context->activeTex = 0; + + glGenTextures(VIDEO_LAYER_MAX, context->tex); + int i; + for (i = 0; i < VIDEO_LAYER_MAX; ++i) { + glBindTexture(GL_TEXTURE_2D, context->layers[i]); + _initTex(); + } } -static void mGLContextSetDimensions(struct VideoBackend* v, unsigned width, unsigned height) { +static inline void _setTexDims(int width, int height) { +#ifdef COLOR_16_BIT +#ifdef COLOR_5_6_5 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); +#endif +#elif defined(__BIG_ENDIAN__) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +#endif +} + +static void mGLContextSetLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct mRectangle* dims) { struct mGLContext* context = (struct mGLContext*) v; - if (width == v->width && height == v->height) { + if (layer >= VIDEO_LAYER_MAX) { return; } - v->width = width; - v->height = height; + context->layerDims[layer].x = dims->x; + context->layerDims[layer].y = dims->y; + if (dims->width == context->layerDims[layer].width && dims->height == context->layerDims[layer].height) { + return; + } + context->layerDims[layer].width = dims->width; + context->layerDims[layer].height = dims->height; - glBindTexture(GL_TEXTURE_2D, context->tex[0]); -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); -#endif -#elif defined(__BIG_ENDIAN__) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -#endif + if (context->imageSizes[layer].width <= 0 || context->imageSizes[layer].height <= 0) { + if (layer == VIDEO_LAYER_IMAGE) { + glBindTexture(GL_TEXTURE_2D, context->tex[0]); + _setTexDims(dims->width, dims->height); + glBindTexture(GL_TEXTURE_2D, context->tex[1]); + _setTexDims(dims->width, dims->height); + } else { + glBindTexture(GL_TEXTURE_2D, context->layers[layer]); + _setTexDims(dims->width, dims->height); + } + } +} - glBindTexture(GL_TEXTURE_2D, context->tex[1]); -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); -#endif -#elif defined(__BIG_ENDIAN__) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -#endif +static void mGLContextLayerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct mRectangle* dims) { + struct mGLContext* context = (struct mGLContext*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + memcpy(dims, &context->layerDims[layer], sizeof(*dims)); } static void mGLContextDeinit(struct VideoBackend* v) { struct mGLContext* context = (struct mGLContext*) v; glDeleteTextures(2, context->tex); + glDeleteTextures(VIDEO_LAYER_MAX, context->layers); } static void mGLContextResized(struct VideoBackend* v, unsigned w, unsigned h) { unsigned drawW = w; unsigned drawH = h; + + unsigned maxW; + unsigned maxH; + VideoBackendGetFrameSize(v, &maxW, &maxH); + if (v->lockAspectRatio) { - lockAspectRatioUInt(v->width, v->height, &drawW, &drawH); + lockAspectRatioUInt(maxW, maxH, &drawW, &drawH); } if (v->lockIntegerScaling) { - lockIntegerRatioUInt(v->width, &drawW); - lockIntegerRatioUInt(v->height, &drawH); + lockIntegerRatioUInt(maxW, &drawW); + lockIntegerRatioUInt(maxH, &drawH); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -105,33 +131,7 @@ static void mGLContextClear(struct VideoBackend* v) { glClear(GL_COLOR_BUFFER_BIT); } -void mGLContextDrawFrame(struct VideoBackend* v) { - struct mGLContext* context = (struct mGLContext*) v; - glEnable(GL_TEXTURE_2D); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_INT, 0, _glVertices); - glTexCoordPointer(2, GL_INT, 0, _glTexCoords); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, v->width, v->height, 0, 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - if (v->interframeBlending) { - glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); - glBlendColor(1, 1, 1, 0.5); - glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex ^ 1]); - if (v->filter) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glEnable(GL_BLEND); - } - glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]); +static void _setFilter(struct VideoBackend* v) { if (v->filter) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -139,36 +139,157 @@ void mGLContextDrawFrame(struct VideoBackend* v) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisable(GL_BLEND); } -void mGLContextPostFrame(struct VideoBackend* v, const void* frame) { +static void _setFrame(struct mRectangle* dims, struct mRectangle* frame) { + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + glScissor(viewport[0] + (dims->x - frame->x) * viewport[2] / frame->width, + viewport[1] + (frame->height + frame->y - dims->height - dims->y) * viewport[3] / frame->height, + dims->width * viewport[2] / frame->width, + dims->height * viewport[3] / frame->height); + glLoadIdentity(); + glTranslatef(dims->x, dims->y, 0); + glScalef(toPow2(dims->width), toPow2(dims->height), 1); +} + +static void _drawLayers(struct mGLContext* context, int start, int end) { + struct mRectangle frame; + VideoBackendGetFrame(&context->d, &frame); + + int layer; + for (layer = start; layer < end; ++layer) { + if (context->layerDims[layer].width < 1 || context->layerDims[layer].height < 1) { + continue; + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, context->layers[layer]); + _setFilter(&context->d); + _setFrame(&context->layerDims[layer], &frame); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } +} + +void mGLContextDrawFrame(struct VideoBackend* v) { struct mGLContext* context = (struct mGLContext*) v; - context->activeTex ^= 1; + glEnable(GL_TEXTURE_2D); + glEnable(GL_SCISSOR_TEST); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_INT, 0, _glVertices); + glTexCoordPointer(2, GL_INT, 0, _glTexCoords); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + struct mRectangle frame; + VideoBackendGetFrame(v, &frame); + glOrtho(frame.x, frame.x + frame.width, frame.y + frame.height, frame.y, 0, 1); + glMatrixMode(GL_MODELVIEW); + + _drawLayers(context, 0, VIDEO_LAYER_IMAGE); + + _setFrame(&context->layerDims[VIDEO_LAYER_IMAGE], &frame); + glDisable(GL_BLEND); + if (v->interframeBlending) { + glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex ^ 1]); + _setFilter(v); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glEnable(GL_BLEND); + glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); + glBlendColor(1, 1, 1, 0.5); + } + glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]); + _setFilter(v); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _drawLayers(context, VIDEO_LAYER_IMAGE + 1, VIDEO_LAYER_MAX); +} + +static void mGLContextSetImageSize(struct VideoBackend* v, enum VideoLayer layer, int width, int height) { + struct mGLContext* context = (struct mGLContext*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + if (width <= 0 || height <= 0) { + context->imageSizes[layer].width = -1; + context->imageSizes[layer].height = -1; + width = context->layerDims[layer].width; + height = context->layerDims[layer].height; + } else { + context->imageSizes[layer].width = width; + context->imageSizes[layer].height = height; + } + if (layer == VIDEO_LAYER_IMAGE) { + glBindTexture(GL_TEXTURE_2D, context->tex[0]); + _setTexDims(width, height); + glBindTexture(GL_TEXTURE_2D, context->tex[1]); + _setTexDims(width, height); + } else { + glBindTexture(GL_TEXTURE_2D, context->layers[layer]); + _setTexDims(width, height); + } +} + +static void mGLContextImageSize(struct VideoBackend* v, enum VideoLayer layer, int* width, int* height) { + struct mGLContext* context = (struct mGLContext*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + + if (context->imageSizes[layer].width <= 0 || context->imageSizes[layer].height <= 0) { + *width = context->layerDims[layer].width; + *height = context->layerDims[layer].height; + } else { + *width = context->imageSizes[layer].width; + *height = context->imageSizes[layer].height; + } +} + +void mGLContextPostFrame(struct VideoBackend* v, enum VideoLayer layer, const void* frame) { + struct mGLContext* context = (struct mGLContext*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + if (layer == VIDEO_LAYER_IMAGE) { + context->activeTex ^= 1; + glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]); + } else { + glBindTexture(GL_TEXTURE_2D, context->layers[layer]); + } + + int width = context->imageSizes[layer].width; + int height = context->imageSizes[layer].height; + + if (width <= 0 || height <= 0) { + width = context->layerDims[layer].width; + height = context->layerDims[layer].height; + } #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); #else - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); #endif #elif defined(__BIG_ENDIAN__) - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame); #else - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, frame); #endif } void mGLContextCreate(struct mGLContext* context) { context->d.init = mGLContextInit; context->d.deinit = mGLContextDeinit; - context->d.setDimensions = mGLContextSetDimensions; - context->d.resized = mGLContextResized; - context->d.swap = 0; + context->d.setLayerDimensions = mGLContextSetLayerDimensions; + context->d.layerDimensions = mGLContextLayerDimensions; + context->d.contextResized = mGLContextResized; + context->d.swap = NULL; context->d.clear = mGLContextClear; - context->d.postFrame = mGLContextPostFrame; + context->d.setImageSize = mGLContextSetImageSize; + context->d.imageSize = mGLContextImageSize; + context->d.setImage = mGLContextPostFrame; context->d.drawFrame = mGLContextDrawFrame; - context->d.setMessage = 0; - context->d.clearMessage = 0; } diff --git a/src/platform/opengl/gl.h b/src/platform/opengl/gl.h index 3ff528864..28bb5249d 100644 --- a/src/platform/opengl/gl.h +++ b/src/platform/opengl/gl.h @@ -21,13 +21,16 @@ CXX_GUARD_START #include #endif -#include "platform/video-backend.h" +#include struct mGLContext { struct VideoBackend d; - GLuint tex[2]; int activeTex; + GLuint tex[2]; + GLuint layers[VIDEO_LAYER_MAX]; + struct mRectangle layerDims[VIDEO_LAYER_MAX]; + struct mSize imageSizes[VIDEO_LAYER_MAX]; }; void mGLContextCreate(struct mGLContext*); diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index 4277b7b76..51180813e 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -81,6 +81,15 @@ static const char* const _nullFragmentShader = " gl_FragColor = color;\n" "}"; +static const char* const _thruFragmentShader = + "varying vec2 texCoord;\n" + "uniform sampler2D tex;\n" + + "void main() {\n" + " vec4 color = texture2D(tex, texCoord);\n" + " gl_FragColor = color;\n" + "}"; + static const char* const _interframeFragmentShader = "varying vec2 texCoord;\n" "uniform sampler2D tex;\n" @@ -101,12 +110,19 @@ static const GLfloat _vertices[] = { static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { UNUSED(handle); struct mGLES2Context* context = (struct mGLES2Context*) v; - v->width = 1; - v->height = 1; - glGenTextures(1, &context->tex); - glBindTexture(GL_TEXTURE_2D, context->tex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + memset(context->layerDims, 0, sizeof(context->layerDims)); + + glGenTextures(VIDEO_LAYER_MAX, context->tex); + int i; + for (i = 0; i < VIDEO_LAYER_MAX; ++i) { + glBindTexture(GL_TEXTURE_2D, context->tex[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + context->imageSizes[i].width = -1; + context->imageSizes[i].height = -1; + } + context->width = 1; + context->height = 1; glGenBuffers(1, &context->vbo); glBindBuffer(GL_ARRAY_BUFFER, context->vbo); @@ -156,8 +172,9 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { uniforms[3].max.fvec3[1] = 1.0f; uniforms[3].max.fvec3[2] = 1.0f; mGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, false, uniforms, 4); - mGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, false, 0, 0); - mGLES2ShaderInit(&context->interframeShader, 0, _interframeFragmentShader, -1, -1, false, 0, 0); + mGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, false, NULL, 0); + mGLES2ShaderInit(&context->interframeShader, 0, _interframeFragmentShader, -1, -1, false, NULL, 0); + mGLES2ShaderInit(&context->overlayShader, _vertexShader, _thruFragmentShader, -1, -1, false, NULL, 0); #ifdef BUILD_GLES3 if (context->initialShader.vao != (GLuint) -1) { @@ -167,25 +184,24 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) { glBindBuffer(GL_ARRAY_BUFFER, context->vbo); glBindVertexArray(context->interframeShader.vao); glBindBuffer(GL_ARRAY_BUFFER, context->vbo); + glBindVertexArray(context->overlayShader.vao); + glBindBuffer(GL_ARRAY_BUFFER, context->vbo); glBindVertexArray(0); } #endif + glDeleteFramebuffers(1, &context->overlayShader.fbo); + glDeleteTextures(1, &context->overlayShader.tex); + context->overlayShader.fbo = context->initialShader.fbo; + context->overlayShader.tex = context->initialShader.tex; + glDeleteFramebuffers(1, &context->finalShader.fbo); glDeleteTextures(1, &context->finalShader.tex); context->finalShader.fbo = 0; context->finalShader.tex = 0; } -static void mGLES2ContextSetDimensions(struct VideoBackend* v, unsigned width, unsigned height) { - struct mGLES2Context* context = (struct mGLES2Context*) v; - if (width == v->width && height == v->height) { - return; - } - v->width = width; - v->height = height; - - glBindTexture(GL_TEXTURE_2D, context->tex); +static inline void _setTexDims(int width, int height) { #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); @@ -197,24 +213,61 @@ static void mGLES2ContextSetDimensions(struct VideoBackend* v, unsigned width, u #else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); #endif +} - size_t n; - for (n = 0; n < context->nShaders; ++n) { - if (context->shaders[n].width < 0 || context->shaders[n].height < 0) { - context->shaders[n].dirty = true; +static void mGLES2ContextSetLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct mRectangle* dims) { + struct mGLES2Context* context = (struct mGLES2Context*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + if (dims->width != context->layerDims[layer].width && dims->height != context->layerDims[layer].height) { + context->layerDims[layer].width = dims->width; + context->layerDims[layer].height = dims->height; + + glBindTexture(GL_TEXTURE_2D, context->tex[layer]); + if (context->imageSizes[layer].width <= 0 || context->imageSizes[layer].height <= 0) { + _setTexDims(dims->width, dims->height); } } - context->initialShader.dirty = true; - context->interframeShader.dirty = true; + + context->layerDims[layer].x = dims->x; + context->layerDims[layer].y = dims->y; + + struct mRectangle frame; + VideoBackendGetFrame(v, &frame); + if (frame.width != context->width || frame.height != context->height) { + size_t n; + for (n = 0; n < context->nShaders; ++n) { + if (context->shaders[n].width < 0 || context->shaders[n].height < 0) { + context->shaders[n].dirty = true; + } + } + glBindTexture(GL_TEXTURE_2D, context->initialShader.tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, frame.width, frame.height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + context->width = frame.width; + context->height = frame.height; + } + context->x = frame.x; + context->y = frame.y; +} + +static void mGLES2ContextLayerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct mRectangle* dims) { + struct mGLES2Context* context = (struct mGLES2Context*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + memcpy(dims, &context->layerDims[layer], sizeof(*dims)); } static void mGLES2ContextDeinit(struct VideoBackend* v) { struct mGLES2Context* context = (struct mGLES2Context*) v; - glDeleteTextures(1, &context->tex); + glDeleteTextures(VIDEO_LAYER_MAX, context->tex); glDeleteBuffers(1, &context->vbo); mGLES2ShaderDeinit(&context->initialShader); mGLES2ShaderDeinit(&context->finalShader); mGLES2ShaderDeinit(&context->interframeShader); + context->overlayShader.fbo = 0; + mGLES2ShaderDeinit(&context->overlayShader); free(context->initialShader.uniforms); } @@ -222,12 +275,16 @@ static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h) struct mGLES2Context* context = (struct mGLES2Context*) v; unsigned drawW = w; unsigned drawH = h; + + unsigned maxW = context->width; + unsigned maxH = context->height; + if (v->lockAspectRatio) { - lockAspectRatioUInt(v->width, v->height, &drawW, &drawH); + lockAspectRatioUInt(maxW, maxH, &drawW, &drawH); } if (v->lockIntegerScaling) { - lockIntegerRatioUInt(v->width, &drawW); - lockIntegerRatioUInt(v->height, &drawH); + lockIntegerRatioUInt(maxW, &drawW); + lockIntegerRatioUInt(maxH, &drawH); } size_t n; for (n = 0; n < context->nShaders; ++n) { @@ -236,6 +293,7 @@ static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h) } } context->finalShader.dirty = true; + context->interframeShader.dirty = true; glBindTexture(GL_TEXTURE_2D, context->finalShader.tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, drawW, drawH, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glBindFramebuffer(GL_FRAMEBUFFER, context->finalShader.fbo); @@ -249,7 +307,7 @@ static void mGLES2ContextClear(struct VideoBackend* v) { glClear(GL_COLOR_BUFFER_BIT); } -void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { +static void _drawShaderEx(struct mGLES2Context* context, struct mGLES2Shader* shader, int layer) { GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); int drawW = shader->width; @@ -260,19 +318,19 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { drawW = viewport[2]; padW = viewport[0]; } else if (shader->width < 0) { - drawW = context->d.width * -shader->width; + drawW = context->width * -shader->width; } if (!drawH) { drawH = viewport[3]; padH = viewport[1]; } else if (shader->height < 0) { - drawH = context->d.height * -shader->height; + drawH = context->height * -shader->height; } if (shader->integerScaling) { padW = 0; padH = 0; - drawW -= drawW % context->d.width; - drawH -= drawH % context->d.height; + drawW -= drawW % context->width; + drawH -= drawH % context->height; } if (shader->dirty) { @@ -286,22 +344,30 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { shader->dirty = false; } + if (layer >= 0 && layer < VIDEO_LAYER_MAX) { + glViewport(context->layerDims[layer].x - context->x, context->height - context->layerDims[layer].y - context->layerDims[layer].height + context->y, context->layerDims[layer].width, context->layerDims[layer].height); + } else { + glViewport(padW, padH, drawW, drawH); + } + glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo); - glViewport(padW, padH, drawW, drawH); if (shader->blend) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); - glClearColor(0.f, 0.f, 0.f, 1.f); - glClear(GL_COLOR_BUFFER_BIT); + if (layer <= VIDEO_LAYER_BACKGROUND) { + glClearColor(0.f, 0.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + } } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST); glUseProgram(shader->program); glUniform1i(shader->texLocation, 0); - glUniform2f(shader->texSizeLocation, context->d.width - padW, context->d.height - padH); + glUniform2f(shader->texSizeLocation, context->width, context->height); + glUniform2f(shader->outputSizeLocation, drawW, drawH); #ifdef BUILD_GLES3 if (shader->vao != (GLuint) -1) { glBindVertexArray(shader->vao); @@ -367,21 +433,41 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { glBindTexture(GL_TEXTURE_2D, shader->tex); } +static void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) { + _drawShaderEx(context, shader, -1); +} + void mGLES2ContextDrawFrame(struct VideoBackend* v) { struct mGLES2Context* context = (struct mGLES2Context*) v; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, context->tex); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); context->finalShader.filter = v->filter; - _drawShader(context, &context->initialShader); - if (v->interframeBlending) { - context->interframeShader.blend = true; - glViewport(0, 0, viewport[2], viewport[3]); - _drawShader(context, &context->interframeShader); + + int layer; + for (layer = 0; layer < VIDEO_LAYER_MAX; ++layer) { + if (context->layerDims[layer].width < 1 || context->layerDims[layer].height < 1) { + continue; + } + glBindTexture(GL_TEXTURE_2D, context->tex[layer]); + if (layer != VIDEO_LAYER_IMAGE) { + context->overlayShader.blend = layer > VIDEO_LAYER_BACKGROUND; + _drawShaderEx(context, &context->overlayShader, layer); + } else { + _drawShaderEx(context, &context->initialShader, layer); + } + if (layer != VIDEO_LAYER_IMAGE) { + continue; + } + if (v->interframeBlending) { + context->interframeShader.blend = true; + glViewport(0, 0, viewport[2], viewport[3]); + _drawShader(context, &context->interframeShader); + } } + size_t n; for (n = 0; n < context->nShaders; ++n) { glViewport(0, 0, viewport[2], viewport[3]); @@ -391,8 +477,8 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) { _drawShader(context, &context->finalShader); if (v->interframeBlending) { context->interframeShader.blend = false; - glBindTexture(GL_TEXTURE_2D, context->tex); - _drawShader(context, &context->initialShader); + glBindTexture(GL_TEXTURE_2D, context->tex[VIDEO_LAYER_IMAGE]); + _drawShaderEx(context, &context->initialShader, VIDEO_LAYER_IMAGE); glViewport(0, 0, viewport[2], viewport[3]); _drawShader(context, &context->interframeShader); } @@ -405,33 +491,79 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) { #endif } -void mGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) { +static void mGLES2ContextSetImageSize(struct VideoBackend* v, enum VideoLayer layer, int width, int height) { struct mGLES2Context* context = (struct mGLES2Context*) v; - glBindTexture(GL_TEXTURE_2D, context->tex); + if (layer >= VIDEO_LAYER_MAX) { + return; + } + + glBindTexture(GL_TEXTURE_2D, context->tex[layer]); + if (width <= 0 || height <= 0) { + context->imageSizes[layer].width = -1; + context->imageSizes[layer].height = -1; + width = context->layerDims[layer].width; + height = context->layerDims[layer].height; + } else { + context->imageSizes[layer].width = width; + context->imageSizes[layer].height = height; + } + _setTexDims(width, height); +} + +static void mGLES2ContextImageSize(struct VideoBackend* v, enum VideoLayer layer, int* width, int* height) { + struct mGLES2Context* context = (struct mGLES2Context*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + + if (context->imageSizes[layer].width <= 0 || context->imageSizes[layer].height <= 0) { + *width = context->layerDims[layer].width; + *height = context->layerDims[layer].height; + } else { + *width = context->imageSizes[layer].width; + *height = context->imageSizes[layer].height; + } +} + +void mGLES2ContextPostFrame(struct VideoBackend* v, enum VideoLayer layer, const void* frame) { + struct mGLES2Context* context = (struct mGLES2Context*) v; + if (layer >= VIDEO_LAYER_MAX) { + return; + } + + int width = context->imageSizes[layer].width; + int height = context->imageSizes[layer].height; + + if (width <= 0 || height <= 0) { + width = context->layerDims[layer].width; + height = context->layerDims[layer].height; + } + glBindTexture(GL_TEXTURE_2D, context->tex[layer]); #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); #endif #elif defined(__BIG_ENDIAN__) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); #endif } void mGLES2ContextCreate(struct mGLES2Context* context) { context->d.init = mGLES2ContextInit; context->d.deinit = mGLES2ContextDeinit; - context->d.setDimensions = mGLES2ContextSetDimensions; - context->d.resized = mGLES2ContextResized; - context->d.swap = 0; + context->d.setLayerDimensions = mGLES2ContextSetLayerDimensions; + context->d.layerDimensions = mGLES2ContextLayerDimensions; + context->d.contextResized = mGLES2ContextResized; + context->d.swap = NULL; context->d.clear = mGLES2ContextClear; - context->d.postFrame = mGLES2ContextPostFrame; + context->d.setImageSize = mGLES2ContextSetImageSize; + context->d.imageSize = mGLES2ContextImageSize; + context->d.setImage = mGLES2ContextPostFrame; context->d.drawFrame = mGLES2ContextDrawFrame; - context->d.setMessage = 0; - context->d.clearMessage = 0; context->shaders = 0; context->nShaders = 0; } @@ -532,6 +664,7 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f shader->texLocation = glGetUniformLocation(shader->program, "tex"); shader->texSizeLocation = glGetUniformLocation(shader->program, "texSize"); shader->positionLocation = glGetAttribLocation(shader->program, "position"); + shader->outputSizeLocation = glGetUniformLocation(shader->program, "outputSize"); size_t i; for (i = 0; i < shader->nUniforms; ++i) { shader->uniforms[i].location = glGetUniformLocation(shader->program, shader->uniforms[i].name); @@ -555,10 +688,14 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f } void mGLES2ShaderDeinit(struct mGLES2Shader* shader) { - glDeleteTextures(1, &shader->tex); + if (shader->tex) { + glDeleteTextures(1, &shader->tex); + } glDeleteShader(shader->fragmentShader); glDeleteProgram(shader->program); - glDeleteFramebuffers(1, &shader->fbo); + if (shader->fbo) { + glDeleteFramebuffers(1, &shader->fbo); + } #ifdef BUILD_GLES3 if (shader->vao != (GLuint) -1) { glDeleteVertexArrays(1, &shader->vao); @@ -1010,8 +1147,11 @@ bool mGLES2ShaderLoad(struct VideoShader* shader, struct VDir* dir) { } } u = mGLES2UniformListSize(&uniformVector); - struct mGLES2Uniform* uniformBlock = calloc(u, sizeof(*uniformBlock)); - memcpy(uniformBlock, mGLES2UniformListGetPointer(&uniformVector, 0), sizeof(*uniformBlock) * u); + struct mGLES2Uniform* uniformBlock = NULL; + if (u) { + uniformBlock = calloc(u, sizeof(*uniformBlock)); + memcpy(uniformBlock, mGLES2UniformListGetPointer(&uniformVector, 0), sizeof(*uniformBlock) * u); + } mGLES2UniformListDeinit(&uniformVector); mGLES2ShaderInit(&shaderBlock[n], vssrc, fssrc, width, height, scaling, uniformBlock, u); @@ -1048,6 +1188,7 @@ bool mGLES2ShaderLoad(struct VideoShader* shader, struct VDir* dir) { for (n = 0; n < inShaders; ++n) { mGLES2ShaderDeinit(&shaderBlock[n]); } + free(shaderBlock); } } } diff --git a/src/platform/opengl/gles2.h b/src/platform/opengl/gles2.h index 144a64a13..e53a1bab5 100644 --- a/src/platform/opengl/gles2.h +++ b/src/platform/opengl/gles2.h @@ -24,7 +24,7 @@ CXX_GUARD_START #include #endif -#include "platform/video-backend.h" +#include union mGLES2UniformValue { GLfloat f; @@ -70,6 +70,7 @@ struct mGLES2Shader { GLuint texLocation; GLuint texSizeLocation; GLuint positionLocation; + GLuint outputSizeLocation; struct mGLES2Uniform* uniforms; size_t nUniforms; @@ -78,12 +79,20 @@ struct mGLES2Shader { struct mGLES2Context { struct VideoBackend d; - GLuint tex; + GLuint tex[VIDEO_LAYER_MAX]; GLuint vbo; + struct mRectangle layerDims[VIDEO_LAYER_MAX]; + struct mSize imageSizes[VIDEO_LAYER_MAX]; + int x; + int y; + int width; + int height; + struct mGLES2Shader initialShader; struct mGLES2Shader finalShader; struct mGLES2Shader interframeShader; + struct mGLES2Shader overlayShader; struct mGLES2Shader* shaders; size_t nShaders; diff --git a/src/platform/psp2/CMakeLists.txt b/src/platform/psp2/CMakeLists.txt index fa9847f14..c42f5355b 100644 --- a/src/platform/psp2/CMakeLists.txt +++ b/src/platform/psp2/CMakeLists.txt @@ -28,6 +28,7 @@ set(OS_LIB -lvita2d -l${M_LIBRARY} -lScePgf_stub -lScePhotoExport_stub -lScePower_stub + -lSceRtc_stub -lSceSysmodule_stub -lSceTouch_stub) set(OS_LIB ${OS_LIB} PARENT_SCOPE) @@ -46,7 +47,7 @@ target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${OS_LIB}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.o COMMAND ${OBJCOPY_CMD} icons2x.png ${CMAKE_CURRENT_BINARY_DIR}/icons.o - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/res) + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/res) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o COMMAND ${OBJCOPY_CMD} backdrop.png ${CMAKE_CURRENT_BINARY_DIR}/backdrop.o diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 747535e25..7b5d0855f 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -231,7 +231,7 @@ int main() { }, { .id = 0 } }, - .nConfigExtra = 2, + .nConfigExtra = 3, .setup = mPSP2Setup, .teardown = mPSP2Teardown, .gameLoaded = mPSP2LoadROM, diff --git a/src/platform/psp2/psp2-context.c b/src/platform/psp2/psp2-context.c index f860bc4a1..a7504f7cc 100644 --- a/src/platform/psp2/psp2-context.c +++ b/src/platform/psp2/psp2-context.c @@ -129,7 +129,7 @@ static THREAD_ENTRY _audioThread(void* context) { sceAudioOutOutput(audioPort, buffer); } sceAudioOutReleasePort(audioPort); - return 0; + THREAD_EXIT(0); } static void _sampleRotation(struct mRotationSource* source) { @@ -323,7 +323,7 @@ void mPSP2Setup(struct mGUIRunner* runner) { mInputBindAxis(&runner->core->inputMap, PSP2_INPUT, 1, &desc); unsigned width, height; - runner->core->desiredVideoDimensions(runner->core, &width, &height); + runner->core->baseVideoSize(runner->core, &width, &height); tex[0] = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); tex[1] = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); currentTex = 0; @@ -614,7 +614,7 @@ void mPSP2Swap(struct mGUIRunner* runner) { void mPSP2Draw(struct mGUIRunner* runner, bool faded) { unsigned width, height; - runner->core->desiredVideoDimensions(runner->core, &width, &height); + runner->core->currentVideoSize(runner->core, &width, &height); if (interframeBlending) { _drawTex(tex[!currentTex], width, height, faded, false); } diff --git a/src/platform/psp2/sce-vfs.c b/src/platform/psp2/sce-vfs.c index 621fd1f67..a98e9943d 100644 --- a/src/platform/psp2/sce-vfs.c +++ b/src/platform/psp2/sce-vfs.c @@ -153,11 +153,10 @@ ssize_t _vfsceSize(struct VFile* vf) { bool _vfsceSync(struct VFile* vf, void* buffer, size_t size) { struct VFileSce* vfsce = (struct VFileSce*) vf; if (buffer && size) { - SceOff cur = sceIoLseek(vfsce->fd, 0, SEEK_CUR); - sceIoLseek(vfsce->fd, 0, SEEK_SET); - int res = sceIoWrite(vfsce->fd, buffer, size); - sceIoLseek(vfsce->fd, cur, SEEK_SET); - return res == size; + int res = sceIoPwrite(vfsce->fd, buffer, size, 0); + if (res < 0 || (size_t) res != size) { + return false; + } } return sceIoSyncByFd(vfsce->fd, 0) >= 0; } @@ -284,7 +283,10 @@ struct VDirSceDevList { static const char* _devs[] = { "ux0:", "ur0:", - "uma0:" + "uma0:", + "imc0:", + "xmc0:", + NULL }; struct VDir* VDeviceList() { @@ -322,7 +324,7 @@ static void _vdlsceRewind(struct VDir* vd) { static struct VDirEntry* _vdlsceListNext(struct VDir* vd) { struct VDirSceDevList* vdl = (struct VDirSceDevList*) vd; - while (vdl->vde.index < 3) { + while (vdl->vde.index < 0 || _devs[vdl->vde.index]) { ++vdl->vde.index; vdl->vde.name = _devs[vdl->vde.index]; SceUID dir = sceIoDopen(vdl->vde.name); diff --git a/src/platform/python/_builder.h b/src/platform/python/_builder.h index 62b5cb870..eef4cf046 100644 --- a/src/platform/python/_builder.h +++ b/src/platform/python/_builder.h @@ -52,7 +52,7 @@ void free(void*); #undef PYEXPORT #ifdef USE_PNG -#include +#include #endif #ifdef M_CORE_GBA #include diff --git a/src/platform/python/_builder.py b/src/platform/python/_builder.py index a69f65616..1e21cc82f 100644 --- a/src/platform/python/_builder.py +++ b/src/platform/python/_builder.py @@ -40,7 +40,7 @@ ffi.set_source("mgba._pylib", """ #include #include #include -#include +#include #include #define PYEXPORT diff --git a/src/platform/python/mgba/core.py b/src/platform/python/mgba/core.py index 3a9b90c3a..51f543d3a 100644 --- a/src/platform/python/mgba/core.py +++ b/src/platform/python/mgba/core.py @@ -235,7 +235,7 @@ class Core(object): def desired_video_dimensions(self): width = ffi.new("unsigned*") height = ffi.new("unsigned*") - self._core.desiredVideoDimensions(self._core, width, height) + self._core.currentVideoSize(self._core, width, height) return width[0], height[0] @protected diff --git a/src/platform/python/mgba/gba.py b/src/platform/python/mgba/gba.py index 09deafc6c..a0c86ac84 100644 --- a/src/platform/python/mgba/gba.py +++ b/src/platform/python/mgba/gba.py @@ -123,19 +123,19 @@ class GBAMemory(Memory): def __init__(self, core, romSize=lib.SIZE_CART0): super(GBAMemory, self).__init__(core, 0x100000000) - self.bios = Memory(core, lib.SIZE_BIOS, lib.BASE_BIOS) - self.wram = Memory(core, lib.SIZE_WORKING_RAM, lib.BASE_WORKING_RAM) - self.iwram = Memory(core, lib.SIZE_WORKING_IRAM, lib.BASE_WORKING_IRAM) - self.io = Memory(core, lib.SIZE_IO, lib.BASE_IO) # pylint: disable=invalid-name - self.palette = Memory(core, lib.SIZE_PALETTE_RAM, lib.BASE_PALETTE_RAM) - self.vram = Memory(core, lib.SIZE_VRAM, lib.BASE_VRAM) - self.oam = Memory(core, lib.SIZE_OAM, lib.BASE_OAM) + self.bios = Memory(core, lib.GBA_SIZE_BIOS, lib.GBA_BASE_BIOS) + self.wram = Memory(core, lib.GBA_SIZE_EWRAM, lib.GBA_BASE_EWRAM) + self.iwram = Memory(core, lib.GBA_SIZE_IWRAM, lib.GBA_BASE_IWRAM) + self.io = Memory(core, lib.GBA_SIZE_IO, lib.GBA_BASE_IO) # pylint: disable=invalid-name + self.palette = Memory(core, lib.GBA_SIZE_PALETTE_RAM, lib.GBA_BASE_PALETTE_RAM) + self.vram = Memory(core, lib.GBA_SIZE_VRAM, lib.GBA_BASE_VRAM) + self.oam = Memory(core, lib.GBA_SIZE_OAM, lib.GBA_BASE_OAM) self.cart0 = Memory(core, romSize, lib.BASE_CART0) self.cart1 = Memory(core, romSize, lib.BASE_CART1) self.cart2 = Memory(core, romSize, lib.BASE_CART2) self.cart = self.cart0 self.rom = self.cart0 - self.sram = Memory(core, lib.SIZE_CART_SRAM, lib.BASE_CART_SRAM) + self.sram = Memory(core, lib.GBA_SIZE_SRAM, lib.GBA_BASE_SRAM) class GBASprite(Sprite): diff --git a/src/platform/python/mgba/png.py b/src/platform/python/mgba/png.py index ac8b79b86..3df4d3cd9 100644 --- a/src/platform/python/mgba/png.py +++ b/src/platform/python/mgba/png.py @@ -21,20 +21,16 @@ class PNG: def write_header(self, image): self._png = lib.PNGWriteOpen(self._vfile.handle) if self.mode == MODE_RGB: - self._info = lib.PNGWriteHeader(self._png, image.width, image.height) + self._info = lib.PNGWriteHeader(self._png, image.width, image.height, lib.mCOLOR_XBGR8) if self.mode == MODE_RGBA: - self._info = lib.PNGWriteHeaderA(self._png, image.width, image.height) - if self.mode == MODE_INDEX: - self._info = lib.PNGWriteHeader8(self._png, image.width, image.height) + self._info = lib.PNGWriteHeader(self._png, image.width, image.height, lib.mCOLOR_ABGR8) return self._info != ffi.NULL def write_pixels(self, image): if self.mode == MODE_RGB: - return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer) + return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer, lib.mCOLOR_XBGR8) if self.mode == MODE_RGBA: - return lib.PNGWritePixelsA(self._png, image.width, image.height, image.stride, image.buffer) - if self.mode == MODE_INDEX: - return lib.PNGWritePixels8(self._png, image.width, image.height, image.stride, image.buffer) + return lib.PNGWritePixels(self._png, image.width, image.height, image.stride, image.buffer, lib.mCOLOR_ABGR8) return False def write_close(self): diff --git a/src/platform/qt/AboutScreen.cpp b/src/platform/qt/AboutScreen.cpp index 1bf672f98..dae9e8dc9 100644 --- a/src/platform/qt/AboutScreen.cpp +++ b/src/platform/qt/AboutScreen.cpp @@ -74,7 +74,7 @@ AboutScreen::AboutScreen(QWidget* parent) { QString copyright = m_ui.copyright->text(); - copyright.replace("{year}", QLatin1String("2022")); + copyright.replace("{year}", QLatin1String("2023")); m_ui.copyright->setText(copyright); } } diff --git a/src/platform/qt/Action.cpp b/src/platform/qt/Action.cpp index e5d6600d4..850b64934 100644 --- a/src/platform/qt/Action.cpp +++ b/src/platform/qt/Action.cpp @@ -12,17 +12,17 @@ Action::Action(QObject* parent) { } -Action::Action(Function function, const QString& name, const QString& visibleName, QObject* parent) +Action::Action(Function&& function, const QString& name, const QString& visibleName, QObject* parent) : QObject(parent) - , m_function(function) + , m_function(std::move(function)) , m_name(name) , m_visibleName(visibleName) { } -Action::Action(Action::BooleanFunction function, const QString& name, const QString& visibleName, QObject* parent) +Action::Action(Action::BooleanFunction&& function, const QString& name, const QString& visibleName, QObject* parent) : QObject(parent) - , m_booleanFunction(function) + , m_booleanFunction(std::move(function)) , m_name(name) , m_visibleName(visibleName) { @@ -57,9 +57,9 @@ Action::Action(Action& other) { } -void Action::connect(Function func) { +void Action::connect(Function&& func) { m_booleanFunction = {}; - m_function = func; + m_function = std::move(func); } void Action::trigger(bool active) { diff --git a/src/platform/qt/Action.h b/src/platform/qt/Action.h index 9fe2f6aa2..ee3d4587d 100644 --- a/src/platform/qt/Action.h +++ b/src/platform/qt/Action.h @@ -24,8 +24,8 @@ public: QUIT, }; - Action(Function, const QString& name, const QString& visibleName, QObject* parent = nullptr); - Action(BooleanFunction, const QString& name, const QString& visibleName, QObject* parent = nullptr); + Action(Function&&, const QString& name, const QString& visibleName, QObject* parent = nullptr); + Action(BooleanFunction&&, const QString& name, const QString& visibleName, QObject* parent = nullptr); Action(const QString& name, const QString& visibleName, QObject* parent = nullptr); Action(QObject* parent = nullptr); @@ -45,7 +45,7 @@ public: return m_name == other.m_name; } - void connect(Function); + void connect(Function&&); bool isEnabled() const { return m_enabled; } bool isActive() const { return m_active; } diff --git a/src/platform/qt/ActionMapper.cpp b/src/platform/qt/ActionMapper.cpp index e0166d5aa..90302c350 100644 --- a/src/platform/qt/ActionMapper.cpp +++ b/src/platform/qt/ActionMapper.cpp @@ -61,7 +61,7 @@ void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* conte rebuildMenu(name, newMenu, context, shortcuts); continue; } - Action* action = &m_actions[actionName]; + auto action = getAction(actionName); QAction* qaction = qmenu->addAction(action->visibleName()); qaction->setEnabled(action->isEnabled()); qaction->setShortcutContext(Qt::WidgetShortcut); @@ -93,22 +93,29 @@ void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* conte qaction->setMenuRole(QAction::QuitRole); break; } - QObject::connect(qaction, &QAction::triggered, [qaction, action](bool enabled) { + + std::weak_ptr weakAction(action); + QObject::connect(qaction, &QAction::triggered, [qaction, weakAction](bool enabled) { + if (weakAction.expired()) { + return; + } + std::shared_ptr action(weakAction.lock()); if (qaction->isCheckable()) { action->trigger(enabled); } else { action->trigger(); } }); - QObject::connect(action, &Action::enabled, qaction, &QAction::setEnabled); - QObject::connect(action, &Action::activated, [qaction, action](bool active) { + QObject::connect(action.get(), &Action::enabled, qaction, &QAction::setEnabled); + QObject::connect(action.get(), &Action::activated, [qaction, weakAction = std::move(weakAction)](bool active) { + std::shared_ptr action(weakAction.lock()); if (qaction->isCheckable()) { qaction->setChecked(active); } else if (active) { action->setActive(false); } }); - QObject::connect(action, &Action::destroyed, qaction, &QAction::deleteLater); + QObject::connect(action.get(), &Action::destroyed, qaction, &QAction::deleteLater); if (shortcut) { QObject::connect(shortcut, &Shortcut::shortcutChanged, qaction, [qaction](int shortcut) { qaction->setShortcut(QKeySequence(shortcut)); @@ -122,8 +129,8 @@ void ActionMapper::addSeparator(const QString& menu) { m_menus[menu].append(QString{}); } -Action* ActionMapper::addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut) { - m_actions.insert(name, act); +std::shared_ptr ActionMapper::addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut) { + m_actions.insert(name, std::make_shared(act)); m_reverseMenus[name] = menu; m_menus[menu].append(name); if (!shortcut.isEmpty()) { @@ -131,38 +138,38 @@ Action* ActionMapper::addAction(const Action& act, const QString& name, const QS } emit actionAdded(name); - return &m_actions[name]; + return getAction(name); } -Action* ActionMapper::addAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu, const QKeySequence& shortcut) { - return addAction(Action(action, name, visibleName), name, menu, shortcut); +std::shared_ptr ActionMapper::addAction(const QString& visibleName, const QString& name, Action::Function&& action, const QString& menu, const QKeySequence& shortcut) { + return addAction(Action(std::move(action), name, visibleName), name, menu, shortcut); } -Action* ActionMapper::addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu) { +std::shared_ptr ActionMapper::addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu) { return addAction(Action([option, variant]() { option->setValue(variant); }, option->name(), visibleName), QString("%1.%2").arg(option->name()).arg(variant.toString()), menu, {}); } -Action* ActionMapper::addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu, const QKeySequence& shortcut) { - return addAction(Action(action, name, visibleName), name, menu, shortcut); +std::shared_ptr ActionMapper::addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction&& action, const QString& menu, const QKeySequence& shortcut) { + return addAction(Action(std::move(action), name, visibleName), name, menu, shortcut); } -Action* ActionMapper::addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu) { +std::shared_ptr ActionMapper::addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu) { return addAction(Action([option](bool value) { option->setValue(value); }, option->name(), visibleName), option->name(), menu, {}); } -Action* ActionMapper::addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu, const QKeySequence& shortcut) { +std::shared_ptr ActionMapper::addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction&& action, const QString& menu, const QKeySequence& shortcut) { m_hiddenActions.insert(name); m_heldActions.insert(name); - return addBooleanAction(visibleName, name, action, menu, shortcut); + return addBooleanAction(visibleName, name, std::move(action), menu, shortcut); } -Action* ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu, const QKeySequence& shortcut) { +std::shared_ptr ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, Action::Function&& action, const QString& menu, const QKeySequence& shortcut) { m_hiddenActions.insert(name); - return addAction(visibleName, name, action, menu, shortcut); + return addAction(visibleName, name, std::move(action), menu, shortcut); } QStringList ActionMapper::menuItems(const QString& menu) const { @@ -180,8 +187,8 @@ QString ActionMapper::menuName(const QString& menu) const { return m_menuNames[menu]; } -Action* ActionMapper::getAction(const QString& itemName) { - return &m_actions[itemName]; +std::shared_ptr ActionMapper::getAction(const QString& itemName) { + return m_actions.value(itemName); } QKeySequence ActionMapper::defaultShortcut(const QString& itemName) { diff --git a/src/platform/qt/ActionMapper.h b/src/platform/qt/ActionMapper.h index b71f1fbda..f1cc3262f 100644 --- a/src/platform/qt/ActionMapper.h +++ b/src/platform/qt/ActionMapper.h @@ -13,6 +13,7 @@ #include #include +#include class QMenu; class QMenuBar; @@ -33,17 +34,17 @@ public: void addSeparator(const QString& menu); - Action* addAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {}); - template Action* addAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu = {}, const QKeySequence& = {}); - Action* addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu = {}); + std::shared_ptr addAction(const QString& visibleName, const QString& name, Action::Function&& action, const QString& menu = {}, const QKeySequence& = {}); + template std::shared_ptr addAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu = {}, const QKeySequence& = {}); + std::shared_ptr addAction(const QString& visibleName, ConfigOption* option, const QVariant& variant, const QString& menu = {}); - Action* addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {}); - Action* addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu = {}); + std::shared_ptr addBooleanAction(const QString& visibleName, const QString& name, Action::BooleanFunction&& action, const QString& menu = {}, const QKeySequence& = {}); + std::shared_ptr addBooleanAction(const QString& visibleName, ConfigOption* option, const QString& menu = {}); - Action* addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {}); + std::shared_ptr addHeldAction(const QString& visibleName, const QString& name, Action::BooleanFunction&& action, const QString& menu = {}, const QKeySequence& = {}); - Action* addHiddenAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {}); - template Action* addHiddenAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu = {}, const QKeySequence& = {}); + std::shared_ptr addHiddenAction(const QString& visibleName, const QString& name, Action::Function&& action, const QString& menu = {}, const QKeySequence& = {}); + template std::shared_ptr addHiddenAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu = {}, const QKeySequence& = {}); bool isHeld(const QString& name) const { return m_heldActions.contains(name); } @@ -51,7 +52,7 @@ public: QString menuFor(const QString& action) const; QString menuName(const QString& menu) const; - Action* getAction(const QString& action); + std::shared_ptr getAction(const QString& action); QKeySequence defaultShortcut(const QString& action); signals: @@ -60,9 +61,9 @@ signals: private: void rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* context, const ShortcutController&); - Action* addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut); + std::shared_ptr addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut); - QHash m_actions; + QHash> m_actions; QHash m_menus; QHash m_reverseMenus; QHash m_menuNames; @@ -72,14 +73,14 @@ private: }; template -Action* ActionMapper::addAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) { +std::shared_ptr ActionMapper::addAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) { return addAction(visibleName, name, [method, obj]() -> void { (obj->*method)(); }, menu, shortcut); } template -Action* ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) { +std::shared_ptr ActionMapper::addHiddenAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) { m_hiddenActions.insert(name); return addAction(visibleName, name, obj, method, menu, shortcut); } diff --git a/src/platform/qt/ApplicationUpdater.cpp b/src/platform/qt/ApplicationUpdater.cpp index 21def050c..7eebe2c57 100644 --- a/src/platform/qt/ApplicationUpdater.cpp +++ b/src/platform/qt/ApplicationUpdater.cpp @@ -100,6 +100,7 @@ ApplicationUpdater::UpdateInfo ApplicationUpdater::currentVersion() { info.version = QLatin1String(projectVersion); info.rev = gitRevision; info.commit = QLatin1String(gitCommit); + info.size = 0; return info; } diff --git a/src/platform/qt/AssetTile.cpp b/src/platform/qt/AssetTile.cpp index bd9f3a188..78db4ccd9 100644 --- a/src/platform/qt/AssetTile.cpp +++ b/src/platform/qt/AssetTile.cpp @@ -51,8 +51,8 @@ void AssetTile::setController(std::shared_ptr controller) { #ifdef M_CORE_GBA case mPLATFORM_GBA: m_addressWidth = 8; - m_addressBase = BASE_VRAM; - m_boundaryBase = BASE_VRAM | 0x10000; + m_addressBase = GBA_BASE_VRAM; + m_boundaryBase = GBA_BASE_VRAM | 0x10000; break; #endif #ifdef M_CORE_GB diff --git a/src/platform/qt/AssetView.cpp b/src/platform/qt/AssetView.cpp index 034b0b420..c648982c6 100644 --- a/src/platform/qt/AssetView.cpp +++ b/src/platform/qt/AssetView.cpp @@ -32,7 +32,6 @@ AssetView::AssetView(std::shared_ptr controller, QWidget* parent connect(controller.get(), &CoreController::frameAvailable, &m_updateTimer, static_cast(&QTimer::start)); - connect(controller.get(), &CoreController::stopping, this, &AssetView::close); connect(controller.get(), &CoreController::stopping, &m_updateTimer, &QTimer::stop); } @@ -200,7 +199,7 @@ bool AssetView::lookupObjGBA(int id, struct ObjInfo* info) { paletteSet = 2; bits = 4; } - ObjInfo newInfo{ + *info = ObjInfo{ tile, width / 8, height / 8, @@ -219,16 +218,15 @@ bool AssetView::lookupObjGBA(int id, struct ObjInfo* info) { int matIndex = GBAObjAttributesBGetMatIndex(obj->b); const GBAOAMMatrix* mat = &gba->video.oam.mat[matIndex]; QTransform invXform(mat->a / 256., mat->c / 256., mat->b / 256., mat->d / 256., 0, 0); - newInfo.xform = invXform.inverted(); + info->xform = invXform.inverted(); } else { - newInfo.hflip = bool(GBAObjAttributesBIsHFlip(obj->b)); - newInfo.vflip = bool(GBAObjAttributesBIsVFlip(obj->b)); + info->hflip = bool(GBAObjAttributesBIsHFlip(obj->b)); + info->vflip = bool(GBAObjAttributesBIsVFlip(obj->b)); } GBARegisterDISPCNT dispcnt = gba->memory.io[0]; // FIXME: Register name can't be imported due to namespacing issues if (!GBARegisterDISPCNTIsObjCharacterMapping(dispcnt)) { - newInfo.stride = 0x20 >> (GBAObjAttributesAGet256Color(obj->a)); + info->stride = 0x20 >> (GBAObjAttributesAGet256Color(obj->a)); }; - *info = newInfo; return true; } #endif @@ -259,7 +257,7 @@ bool AssetView::lookupObjGB(int id, struct ObjInfo* info) { } palette += 8; - ObjInfo newInfo{ + *info = ObjInfo{ tile, 1, height / 8, @@ -274,7 +272,6 @@ bool AssetView::lookupObjGB(int id, struct ObjInfo* info) { bool(GBObjAttributesIsXFlip(obj->attr)), bool(GBObjAttributesIsYFlip(obj->attr)), }; - *info = newInfo; return true; } #endif diff --git a/src/platform/qt/AudioProcessor.cpp b/src/platform/qt/AudioProcessor.cpp index d0b2b1f24..f46e63529 100644 --- a/src/platform/qt/AudioProcessor.cpp +++ b/src/platform/qt/AudioProcessor.cpp @@ -60,11 +60,11 @@ void AudioProcessor::configure(ConfigController* config) { } void AudioProcessor::setInput(std::shared_ptr input) { - m_context = input; - connect(input.get(), &CoreController::stopping, this, &AudioProcessor::stop); - connect(input.get(), &CoreController::fastForwardChanged, this, &AudioProcessor::inputParametersChanged); - connect(input.get(), &CoreController::paused, this, &AudioProcessor::pause); - connect(input.get(), &CoreController::unpaused, this, &AudioProcessor::start); + m_context = std::move(input); + connect(m_context.get(), &CoreController::stopping, this, &AudioProcessor::stop); + connect(m_context.get(), &CoreController::fastForwardChanged, this, &AudioProcessor::inputParametersChanged); + connect(m_context.get(), &CoreController::paused, this, &AudioProcessor::pause); + connect(m_context.get(), &CoreController::unpaused, this, &AudioProcessor::start); } void AudioProcessor::stop() { diff --git a/src/platform/qt/AudioProcessorQt.cpp b/src/platform/qt/AudioProcessorQt.cpp index 3b12d2e07..8d12cd935 100644 --- a/src/platform/qt/AudioProcessorQt.cpp +++ b/src/platform/qt/AudioProcessorQt.cpp @@ -21,7 +21,7 @@ AudioProcessorQt::AudioProcessorQt(QObject* parent) } void AudioProcessorQt::setInput(std::shared_ptr controller) { - AudioProcessor::setInput(controller); + AudioProcessor::setInput(std::move(controller)); if (m_device) { m_device->setInput(input()); if (m_audioOutput) { diff --git a/src/platform/qt/AudioProcessorSDL.cpp b/src/platform/qt/AudioProcessorSDL.cpp index bf0a5dbdd..bfa9782d1 100644 --- a/src/platform/qt/AudioProcessorSDL.cpp +++ b/src/platform/qt/AudioProcessorSDL.cpp @@ -17,7 +17,7 @@ AudioProcessorSDL::AudioProcessorSDL(QObject* parent) } void AudioProcessorSDL::setInput(std::shared_ptr controller) { - AudioProcessor::setInput(controller); + AudioProcessor::setInput(std::move(controller)); if (m_audio.core && input()->core != m_audio.core) { mSDLDeinitAudio(&m_audio); mSDLInitAudio(&m_audio, input()); diff --git a/src/platform/qt/BattleChipModel.cpp b/src/platform/qt/BattleChipModel.cpp index 2acbd9b7f..941b3f547 100644 --- a/src/platform/qt/BattleChipModel.cpp +++ b/src/platform/qt/BattleChipModel.cpp @@ -118,8 +118,7 @@ void BattleChipModel::setFlavor(int flavor) { if (line.trimmed().isEmpty()) { continue; } - QString name = QString::fromUtf8(line).trimmed(); - m_chipIdToName[id] = name; + m_chipIdToName[id] = QString::fromUtf8(line).trimmed(); } } diff --git a/src/platform/qt/BattleChipModel.h b/src/platform/qt/BattleChipModel.h index c0f115896..9c22002ee 100644 --- a/src/platform/qt/BattleChipModel.h +++ b/src/platform/qt/BattleChipModel.h @@ -49,10 +49,10 @@ private: BattleChip createChip(int id) const; QMap m_chipIdToName; - int m_flavor; + int m_flavor = 0; int m_scale = 1; QList m_deck; }; -} \ No newline at end of file +} diff --git a/src/platform/qt/BattleChipView.cpp b/src/platform/qt/BattleChipView.cpp index 83f38db9b..d72f78c41 100644 --- a/src/platform/qt/BattleChipView.cpp +++ b/src/platform/qt/BattleChipView.cpp @@ -24,7 +24,7 @@ using namespace QGBA; BattleChipView::BattleChipView(std::shared_ptr controller, Window* window, QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) - , m_controller(controller) + , m_controller(std::move(controller)) , m_window(window) { m_ui.setupUi(this); @@ -63,7 +63,6 @@ BattleChipView::BattleChipView(std::shared_ptr controller, Windo connect(m_ui.insert, &QAbstractButton::clicked, this, &BattleChipView::reinsert); connect(m_ui.add, &QAbstractButton::clicked, this, &BattleChipView::addChip); connect(m_ui.remove, &QAbstractButton::clicked, this, &BattleChipView::removeChip); - connect(controller.get(), &CoreController::stopping, this, &QWidget::close); connect(m_ui.save, &QAbstractButton::clicked, this, &BattleChipView::saveDeck); connect(m_ui.load, &QAbstractButton::clicked, this, &BattleChipView::loadDeck); connect(m_ui.updateData, &QAbstractButton::clicked, this, &BattleChipView::updateData); diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 1bb8758c7..610fa362d 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -12,8 +12,8 @@ if(BUILD_SDL) link_directories(${SDL2_LIBDIR}) endif() list(APPEND PLATFORM_LIBRARY ${SDL_LIBRARY}) - list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-events.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-audio.c) - include_directories(${SDL_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/src/platform/sdl) + list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${PROJECT_SOURCE_DIR}/src/platform/sdl/sdl-events.c ${PROJECT_SOURCE_DIR}/src/platform/sdl/sdl-audio.c) + include_directories(${SDL_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/src/platform/sdl) endif() if(POLICY CMP0071) @@ -25,8 +25,12 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(QT_LIBRARIES) -find_package(Qt5 COMPONENTS Core Widgets Network Multimedia) -set(QT Qt5) +set(QT_V 5) +find_package(Qt${QT_V} COMPONENTS Core Widgets Network OPTIONAL_COMPONENTS Multimedia) +if(QT_V GREATER_EQUAL 6) + find_package(Qt${QT_V} COMPONENTS OpenGL OpenGLWidgets) +endif() +set(QT Qt${QT_V}) if(NOT BUILD_GL AND NOT BUILD_GLES2 AND NOT BUILD_GLES3) message(WARNING "OpenGL is recommended to build the Qt port") @@ -44,27 +48,29 @@ if(APPLE) endif() if(Qt6Widgets_VERSION) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.14") + set(MIN_VER 10.14) elseif(Qt5Widgets_VERSION MATCHES "^5.15") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.13") + set(MIN_VER 10.13) elseif(Qt5Widgets_VERSION MATCHES "^5.1[234]") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.12") + set(MIN_VER 10.12) elseif(Qt5Widgets_VERSION MATCHES "^5.11") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.11") + set(MIN_VER 10.11) elseif(Qt5Widgets_VERSION MATCHES "^5.(9|10)") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.10") + set(MIN_VER 10.10) elseif(Qt5Widgets_VERSION MATCHES "^5.8") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.9") + set(MIN_VER 10.9) else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.8") + set(MIN_VER 10.8) endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=${MIN_VER}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${MIN_VER}") if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif() endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations -Werror=narrowing") endif() get_target_property(QT_TYPE ${QT}::Core TYPE) @@ -103,10 +109,15 @@ set(SOURCE_FILES GBAApp.cpp GBAKeyEditor.cpp GIFView.cpp - GamepadAxisEvent.cpp - GamepadButtonEvent.cpp - GamepadHatEvent.cpp IOViewer.cpp + input/Gamepad.cpp + input/GamepadAxisEvent.cpp + input/GamepadButtonEvent.cpp + input/GamepadHatEvent.cpp + input/InputDriver.cpp + input/InputSource.cpp + input/InputMapper.cpp + input/KeySource.cpp InputController.cpp InputProfile.cpp KeyEditor.cpp @@ -164,6 +175,7 @@ set(UI_FILES LoadSaveState.ui LogView.ui MapView.ui + MemoryAccessLogView.ui MemoryDump.ui MemorySearch.ui MemoryView.ui @@ -194,10 +206,11 @@ set(GB_SRC GBOverride.cpp PrinterView.cpp) -set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt${QT_V}widgets${QT_V}") set(AUDIO_SRC) if(BUILD_SDL) + list(APPEND SOURCE_FILES input/SDLInputDriver.cpp) list(APPEND AUDIO_SRC AudioProcessorSDL.cpp) endif() @@ -213,15 +226,17 @@ if(${QT}Multimedia_FOUND) list(APPEND AUDIO_SRC AudioProcessorQt.cpp AudioDevice.cpp) - list(APPEND SOURCE_FILES - VideoDumper.cpp) + if(QT_V LESS 6) + list(APPEND SOURCE_FILES + VideoDumper.cpp) + endif() if (WIN32 AND QT_STATIC) - list(APPEND QT_LIBRARIES ${QT}::QWindowsAudioPlugin ${QT}::DSServicePlugin ${QT}::QWindowsVistaStylePlugin + list(APPEND QT_LIBRARIES ${QT}::QWindowsAudioPlugin ${QT}::DSServicePlugin ${QT}::QWindowsVistaStylePlugin ${QT}::QJpegPlugin strmiids mfuuid mfplat mf ksguid dxva2 evr d3d9) endif() list(APPEND QT_LIBRARIES ${QT}::Multimedia) list(APPEND QT_DEFINES BUILD_QT_MULTIMEDIA) - set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5multimedia5") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt${QT_V}multimedia${QT_V}") endif() if(NOT AUDIO_SRC) @@ -234,7 +249,8 @@ if(USE_DEBUGGERS) list(APPEND SOURCE_FILES DebuggerController.cpp DebuggerConsole.cpp - DebuggerConsoleController.cpp) + DebuggerConsoleController.cpp + MemoryAccessLogView.cpp) endif() if(USE_GDB_STUB) @@ -293,7 +309,7 @@ if(APPLE) set(MACOSX_BUNDLE_BUNDLE_VERSION ${LIB_VERSION_STRING}) set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME}) set(MACOSX_BUNDLE_GUI_IDENTIFIER com.endrift.${BINARY_NAME}-qt) - set_source_files_properties(${CMAKE_SOURCE_DIR}/res/mgba.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + set_source_files_properties(${PROJECT_SOURCE_DIR}/res/mgba.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) if(DISTBUILD) set(APPDIR ".") else() @@ -301,13 +317,13 @@ if(APPLE) endif() endif() if(WIN32) - configure_file(${CMAKE_SOURCE_DIR}/res/mgba.rc.in ${CMAKE_BINARY_DIR}/res/mgba.rc) + configure_file(${PROJECT_SOURCE_DIR}/res/mgba.rc.in ${CMAKE_BINARY_DIR}/res/mgba.rc) list(APPEND RESOURCES ${CMAKE_BINARY_DIR}/res/mgba.rc) - set_source_files_properties(${CMAKE_BINARY_DIR}/res/mgba.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/res/mgba.ico) + set_source_files_properties(${CMAKE_BINARY_DIR}/res/mgba.rc PROPERTIES OBJECT_DEPENDS ${PROJECT_SOURCE_DIR}/res/mgba.ico) endif() if(NOT DEFINED DATADIR) if(APPLE) - set(DATADIR ${APPDIR}/${PROJECT_NAME}.app/Contents/Resources) + set(DATADIR ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.app/Contents/Resources) elseif(WIN32 AND NOT WIN32_UNIX_PATHS) set(DATADIR ".") else() @@ -315,12 +331,24 @@ if(NOT DEFINED DATADIR) endif() endif() if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY) - install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) + if(NOT USE_LIBZIP AND NOT USE_MINIZIP) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) + else() + file(GLOB SHADERS ${PROJECT_SOURCE_DIR}/res/shaders/*.shader) + message(STATUS ${SHADERS}) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/shaders) + foreach(SHADER_DIR ${SHADERS}) + get_filename_component(SHADER ${SHADER_DIR} NAME) + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER}" COMMAND "${CMAKE_COMMAND}" -E tar cf "${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER}" --format=zip . WORKING_DIRECTORY "${SHADER_DIR}") + add_custom_target("${SHADER}" ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER}") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER}" DESTINATION ${DATADIR}/shaders COMPONENT ${BINARY_NAME}-qt) + endforeach() + endif() endif() if(ENABLE_SCRIPTING AND USE_LUA) - install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/scripts DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/res/scripts DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) endif() -install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) +install(FILES ${PROJECT_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) if(NOT WIN32 AND NOT APPLE) if(DATADIR MATCHES "^\\.[.\\]") list(APPEND QT_DEFINES DATADIR="${DATADIR}") @@ -386,8 +414,8 @@ else() qt5_wrap_ui(UI_SRC ${UI_FILES}) endif() -add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR}/res/mgba.icns ${SOURCE_FILES} ${PLATFORM_SRC} ${UI_SRC} ${AUDIO_SRC} ${RESOURCES}) -set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") +add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${PROJECT_SOURCE_DIR}/res/mgba.icns ${SOURCE_FILES} ${PLATFORM_SRC} ${UI_SRC} ${AUDIO_SRC} ${RESOURCES}) +set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") if(WIN32) set_target_properties(${BINARY_NAME}-qt PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") @@ -397,6 +425,9 @@ if(WIN32) endif() list(APPEND QT_LIBRARIES ${QT}::Widgets ${QT}::Network) +if(${QT_V} GREATER_EQUAL 6) + list(APPEND QT_LIBRARIES ${QT}::OpenGL ${QT}::OpenGLWidgets) +endif() if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY) list(APPEND QT_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY}) endif() @@ -420,20 +451,17 @@ if(QT_STATIC) list(APPEND QT_LIBRARIES "-framework AVFoundation" "-framework CoreMedia" "-framework SystemConfiguration" "-framework Security") set_target_properties(${QT}::Core PROPERTIES INTERFACE_LINK_LIBRARIES "${QTPCRE}") elseif(UNIX) - list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa) + list(APPEND QT_LIBRARIES ${QT}::FontDatabaseSupport ${QT}::XcbQpa ${QT}::QWaylandIntegrationPlugin) endif() endif() target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE) -install(TARGETS ${BINARY_NAME}-qt - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt - BUNDLE DESTINATION ${APPDIR} COMPONENT ${BINARY_NAME}-qt) if(UNIX AND NOT APPLE) - install(FILES ${CMAKE_SOURCE_DIR}/res/mgba-qt.desktop DESTINATION share/applications RENAME io.mgba.${PROJECT_NAME}.desktop COMPONENT ${BINARY_NAME}-qt) + install(FILES ${PROJECT_SOURCE_DIR}/res/mgba-qt.desktop DESTINATION share/applications RENAME io.mgba.${PROJECT_NAME}.desktop COMPONENT ${BINARY_NAME}-qt) endif() if(UNIX AND NOT (APPLE AND DISTBUILD)) - install(FILES ${CMAKE_SOURCE_DIR}/doc/mgba-qt.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-qt) + install(FILES ${PROJECT_SOURCE_DIR}/doc/mgba-qt.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-qt) endif() if(APPLE OR WIN32) set_target_properties(${BINARY_NAME}-qt PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) @@ -454,6 +482,10 @@ if(APPLE) file(GLOB_RECURSE PLUGINS \"${BUNDLE_PATH}/Contents/PlugIns/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") fixup_bundle(\"${BUNDLE_PATH}\" \"${PLUGINS}\" \"\") " COMPONENT ${BINARY_NAME}-qt) + if(CODESIGN_IDENTITY) + install(CODE "execute_process(COMMAND codesign -s \"${CODESIGN_IDENTITY}\" -vf -o runtime --timestamp --entitlements \"${PROJECT_SOURCE_DIR}/res/entitlements.plist\" \"${BUNDLE_PATH}\")" + COMPONENT ${BINARY_NAME}-qt) + endif() else() set(DEPLOY_OPTIONS -p platforms/libqcocoa.dylib,audio/libqtaudio_coreaudio.dylib,mediaservice/libqavfcamera.dylib) if(NOT CMAKE_INSTALL_NAME_TOOL EQUAL "install_name_tool") @@ -465,7 +497,10 @@ if(APPLE) if(DEFINED CROSS_ROOT) set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -R "${CROSS_ROOT}") endif() - install(CODE "execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/tools/deploy-mac.py\" -v ${DEPLOY_OPTIONS} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${APPDIR}/${PROJECT_NAME}.app\")") + if($ENV{CODESIGN_IDENTITY}) + set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -s "$ENV{CODESIGN_IDENTITY}" -E "${PROJECT_SOURCE_DIR}/res/entitlements.xml") + endif() + install(CODE "execute_process(COMMAND \"${PROJECT_SOURCE_DIR}/tools/deploy-mac.py\" -v ${DEPLOY_OPTIONS} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${APPDIR}/${PROJECT_NAME}.app\")") endif() elseif(WIN32) if(CMAKE_MAJOR_VERSION EQUAL 3 AND CMAKE_MINOR_VERSION EQUAL 8) @@ -474,7 +509,7 @@ elseif(WIN32) endif() if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") find_program(BASH bash) - install(CODE "execute_process(COMMAND \"${BASH}\" \"${CMAKE_SOURCE_DIR}/tools/deploy-win.sh\" \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe\" \"\${CMAKE_INSTALL_PREFIX}\" \"\$ENV{PWD}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")" COMPONENT ${BINARY_NAME}-qt) + install(CODE "execute_process(COMMAND \"${BASH}\" \"${PROJECT_SOURCE_DIR}/tools/deploy-win.sh\" \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe\" \"\${CMAKE_INSTALL_PREFIX}\" \"\$ENV{PWD}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")" COMPONENT ${BINARY_NAME}-qt) endif() if(DISTBUILD) file(WRITE "${CMAKE_BINARY_DIR}/portable.ini" "") @@ -492,3 +527,7 @@ if(DISTBUILD AND NOT APPLE) add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${STRIP}" "$") endif() endif() + +install(TARGETS ${BINARY_NAME}-qt + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt + BUNDLE DESTINATION ${APPDIR} COMPONENT ${BINARY_NAME}-qt) diff --git a/src/platform/qt/CheatsView.cpp b/src/platform/qt/CheatsView.cpp index e73b52955..243987d6b 100644 --- a/src/platform/qt/CheatsView.cpp +++ b/src/platform/qt/CheatsView.cpp @@ -41,7 +41,6 @@ CheatsView::CheatsView(std::shared_ptr controller, QWidget* pare connect(m_ui.addSet, &QAbstractButton::clicked, this, &CheatsView::addSet); connect(m_ui.remove, &QAbstractButton::clicked, this, &CheatsView::removeSet); connect(m_ui.add, &QAbstractButton::clicked, this, &CheatsView::enterCheat); - connect(controller.get(), &CoreController::stopping, this, &CheatsView::close); connect(controller.get(), &CoreController::stateLoaded, &m_model, &CheatsModel::invalidated); switch (controller->platform()) { diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index 1116dba79..e1bf35408 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -19,6 +19,9 @@ static const mOption s_frontendOptions[] = { { "ecard", true, '\0' }, { "mb", true, '\0' }, +#ifdef ENABLE_SCRIPTING + { "script", true, '\0' }, +#endif { 0 } }; @@ -31,14 +34,14 @@ ConfigOption::ConfigOption(const QString& name, QObject* parent) } void ConfigOption::connect(std::function slot, QObject* parent) { - m_slots[parent] = slot; + m_slots[parent] = std::move(slot); QObject::connect(parent, &QObject::destroyed, this, [this, parent]() { m_slots.remove(parent); }); } -Action* ConfigOption::addValue(const QString& text, const QVariant& value, ActionMapper* actions, const QString& menu) { - Action* action; +std::shared_ptr ConfigOption::addValue(const QString& text, const QVariant& value, ActionMapper* actions, const QString& menu) { + std::shared_ptr action; auto function = [this, value]() { emit valueChanged(value); }; @@ -46,32 +49,42 @@ Action* ConfigOption::addValue(const QString& text, const QVariant& value, Actio if (actions) { action = actions->addAction(text, name, function, menu); } else { - action = new Action(function, name, text, this); + action = std::make_shared(function, name, text, this); } action->setExclusive(); - QObject::connect(action, &QObject::destroyed, this, [this, action, value]() { + std::weak_ptr weakAction(action); + QObject::connect(action.get(), &QObject::destroyed, this, [this, weakAction = std::move(weakAction), value]() { + if (weakAction.expired()) { + return; + } + std::shared_ptr action(weakAction.lock()); m_actions.removeAll(std::make_pair(action, value)); }); m_actions.append(std::make_pair(action, value)); return action; } -Action* ConfigOption::addValue(const QString& text, const char* value, ActionMapper* actions, const QString& menu) { +std::shared_ptr ConfigOption::addValue(const QString& text, const char* value, ActionMapper* actions, const QString& menu) { return addValue(text, QString(value), actions, menu); } -Action* ConfigOption::addBoolean(const QString& text, ActionMapper* actions, const QString& menu) { - Action* action; +std::shared_ptr ConfigOption::addBoolean(const QString& text, ActionMapper* actions, const QString& menu) { + std::shared_ptr action; auto function = [this](bool value) { emit valueChanged(value); }; if (actions) { action = actions->addBooleanAction(text, m_name, function, menu); } else { - action = new Action(function, m_name, text, this); + action = std::make_shared(function, m_name, text, this); } - QObject::connect(action, &QObject::destroyed, this, [this, action]() { + std::weak_ptr weakAction(action); + QObject::connect(action.get(), &QObject::destroyed, this, [this, weakAction]() { + if (weakAction.expired()) { + return; + } + std::shared_ptr action(weakAction.lock()); m_actions.removeAll(std::make_pair(action, QVariant(1))); }); m_actions.append(std::make_pair(action, QVariant(1))); @@ -96,7 +109,7 @@ void ConfigOption::setValue(const char* value) { } void ConfigOption::setValue(const QVariant& value) { - for (std::pair& action : m_actions) { + for (std::pair, QVariant>& action : m_actions) { action.first->setActive(value == action.second); } for (std::function& slot : m_slots.values()) { @@ -125,6 +138,7 @@ ConfigController::ConfigController(QObject* parent) m_opts.logLevel = mLOG_WARN | mLOG_ERROR | mLOG_FATAL; m_opts.rewindEnable = false; m_opts.rewindBufferCapacity = 300; + m_opts.rewindBufferInterval = 1; m_opts.useBios = true; m_opts.suspendScreensaver = true; m_opts.lockAspectRatio = true; @@ -142,7 +156,12 @@ ConfigController::ConfigController(QObject* parent) m_subparsers[1].usage = "Frontend options:\n" " --ecard FILE Scan an e-Reader card in the first loaded game\n" " Can be passed multiple times for multiple cards\n" - " --mb FILE Boot a multiboot image with FILE inserted into the ROM slot"; + " --mb FILE Boot a multiboot image with FILE inserted into the ROM slot" +#ifdef ENABLE_SCRIPTING + "\n --script FILE Script file to load on start" +#endif + ; + m_subparsers[1].parse = nullptr; m_subparsers[1].parseLong = [](struct mSubParser* parser, const char* option, const char* arg) { ConfigController* self = static_cast(parser->opts); @@ -160,6 +179,17 @@ ConfigController::ConfigController(QObject* parent) self->m_argvOptions[optionName] = QString::fromUtf8(arg); return true; } +#ifdef ENABLE_SCRIPTING + if (optionName == QLatin1String("script")) { + QStringList scripts; + if (self->m_argvOptions.contains(optionName)) { + scripts = self->m_argvOptions[optionName].toStringList(); + } + scripts.append(QString::fromUtf8(arg)); + self->m_argvOptions[optionName] = scripts; + return true; + } +#endif return false; }; m_subparsers[1].apply = nullptr; @@ -343,6 +373,7 @@ constexpr const char* ConfigController::mruName(ConfigController::MRU mru) { case MRU::Script: return "recentScripts"; } + Q_UNREACHABLE(); } void ConfigController::write() { @@ -354,7 +385,7 @@ void ConfigController::write() { } void ConfigController::makePortable() { - mCoreConfigMakePortable(&m_config); + mCoreConfigMakePortable(&m_config, nullptr); QString fileName(configDir()); fileName.append(QDir::separator()); diff --git a/src/platform/qt/ConfigController.h b/src/platform/qt/ConfigController.h index ecd126867..4c71c3943 100644 --- a/src/platform/qt/ConfigController.h +++ b/src/platform/qt/ConfigController.h @@ -38,9 +38,9 @@ public: void connect(std::function, QObject* parent = nullptr); - Action* addValue(const QString& text, const QVariant& value, ActionMapper* actions = nullptr, const QString& menu = {}); - Action* addValue(const QString& text, const char* value, ActionMapper* actions = nullptr, const QString& menu = {}); - Action* addBoolean(const QString& text, ActionMapper* actions = nullptr, const QString& menu = {}); + std::shared_ptr addValue(const QString& text, const QVariant& value, ActionMapper* actions = nullptr, const QString& menu = {}); + std::shared_ptr addValue(const QString& text, const char* value, ActionMapper* actions = nullptr, const QString& menu = {}); + std::shared_ptr addBoolean(const QString& text, ActionMapper* actions = nullptr, const QString& menu = {}); QString name() const { return m_name; } @@ -56,7 +56,7 @@ signals: private: QHash> m_slots; - QList> m_actions; + QList, QVariant>> m_actions; QString m_name; }; diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 37fc1b01f..2e2bd5fed 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -49,6 +49,10 @@ CoreController::CoreController(mCore* core, QObject* parent) GBASIODolphinCreate(&m_dolphin); #endif +#ifdef USE_DEBUGGERS + mDebuggerInit(&m_debugger); +#endif + m_resetActions.append([this]() { if (m_autoload) { mCoreLoadState(m_threadContext.core, 0, m_loadStateFlags); @@ -75,20 +79,20 @@ CoreController::CoreController(mCore* core, QObject* parent) controller->updatePlayerSave(); } + if (controller->m_override) { + controller->m_override->identify(context->core); + context->core->setOverride(context->core, controller->m_override->raw()); + } + QMetaObject::invokeMethod(controller, "started"); }; m_threadContext.resetCallback = [](mCoreThread* context) { CoreController* controller = static_cast(context->userData); - for (auto action : controller->m_resetActions) { + for (auto& action : controller->m_resetActions) { action(); } - if (controller->m_override) { - controller->m_override->identify(context->core); - controller->m_override->apply(context->core); - } - controller->m_resetActions.clear(); controller->m_frameCounter = -1; @@ -214,6 +218,10 @@ CoreController::~CoreController() { mCoreThreadJoin(&m_threadContext); +#ifdef USE_DEBUGGERS + mDebuggerDeinit(&m_debugger); +#endif + if (m_cacheSet) { mCacheSetDeinit(m_cacheSet.get()); m_cacheSet.reset(); @@ -223,6 +231,11 @@ CoreController::~CoreController() { m_threadContext.core->deinit(m_threadContext.core); } +void CoreController::setPath(const QString& path, const QString& base) { + m_path = path; + m_baseDirectory = base; +} + const color_t* CoreController::drawContext() { if (m_hwaccel) { return nullptr; @@ -266,11 +279,15 @@ mPlatform CoreController::platform() const { QSize CoreController::screenDimensions() const { unsigned width, height; - m_threadContext.core->desiredVideoDimensions(m_threadContext.core, &width, &height); + m_threadContext.core->currentVideoSize(m_threadContext.core, &width, &height); return QSize(width, height); } +unsigned CoreController::videoScale() const { + return m_threadContext.core->videoScale(m_threadContext.core); +} + void CoreController::loadConfig(ConfigController* config) { Interrupter interrupter(this); m_loadStateFlags = config->getOption("loadStateExtdata", m_loadStateFlags).toInt(); @@ -289,13 +306,6 @@ void CoreController::loadConfig(ConfigController* config) { mCoreConfigCopyValue(&m_threadContext.core->config, config->config(), "mute"); m_preload = config->getOption("preload").toInt(); - int playerId = m_multiplayer->playerId(this) + 1; - QVariant savePlayerId = config->getOption("savePlayerId"); - if (m_multiplayer->attached() < 2 && savePlayerId.canConvert()) { - playerId = savePlayerId.toInt(); - } - mCoreConfigSetOverrideIntValue(&m_threadContext.core->config, "savePlayerId", playerId); - QSize sizeBefore = screenDimensions(); m_activeBuffer.resize(256 * 224 * sizeof(color_t)); m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast(m_activeBuffer.data()), sizeBefore.width()); @@ -322,14 +332,35 @@ void CoreController::loadConfig(ConfigController* config) { } #ifdef USE_DEBUGGERS -void CoreController::setDebugger(mDebugger* debugger) { +void CoreController::attachDebugger(bool interrupt) { Interrupter interrupter(this); - if (debugger) { - mDebuggerAttach(debugger, m_threadContext.core); - mDebuggerEnter(debugger, DEBUGGER_ENTER_ATTACHED, 0); - } else { - m_threadContext.core->detachDebugger(m_threadContext.core); + if (!m_threadContext.core->debugger) { + mDebuggerAttach(&m_debugger, m_threadContext.core); } + if (interrupt) { + mDebuggerEnter(&m_debugger, DEBUGGER_ENTER_ATTACHED, 0); + } +} + +void CoreController::detachDebugger() { + Interrupter interrupter(this); + if (!m_threadContext.core->debugger) { + return; + } + m_threadContext.core->detachDebugger(m_threadContext.core); +} + +void CoreController::attachDebuggerModule(mDebuggerModule* module, bool interrupt) { + Interrupter interrupter(this); + if (module) { + mDebuggerAttachModule(&m_debugger, module); + } + attachDebugger(interrupt); +} + +void CoreController::detachDebuggerModule(mDebuggerModule* module) { + Interrupter interrupter(this); + mDebuggerDetachModule(&m_debugger, module); } #endif @@ -448,7 +479,7 @@ void CoreController::start() { void CoreController::stop() { setSync(false); #ifdef USE_DEBUGGERS - setDebugger(nullptr); + detachDebugger(); #endif setPaused(false); mCoreThreadEnd(&m_threadContext); @@ -518,9 +549,6 @@ void CoreController::setRewinding(bool rewind) { } void CoreController::rewind(int states) { - if (!states) { - return; - } if (!m_threadContext.core->opts.rewindEnable) { emit statusPosted(tr("Rewinding not currently enabled")); } @@ -785,10 +813,16 @@ void CoreController::loadSave(const QString& path, bool temporary) { return; } + bool ok; if (temporary) { - m_threadContext.core->loadTemporarySave(m_threadContext.core, vf); + ok = m_threadContext.core->loadTemporarySave(m_threadContext.core, vf); } else { - m_threadContext.core->loadSave(m_threadContext.core, vf); + ok = m_threadContext.core->loadSave(m_threadContext.core, vf); + } + if (!ok) { + vf->close(vf); + } else { + m_savePath = path; } }); if (hasStarted()) { @@ -796,12 +830,18 @@ void CoreController::loadSave(const QString& path, bool temporary) { } } -void CoreController::loadSave(VFile* vf, bool temporary) { - m_resetActions.append([this, vf, temporary]() { +void CoreController::loadSave(VFile* vf, bool temporary, const QString& path) { + m_resetActions.append([this, vf, temporary, path]() { + bool ok; if (temporary) { - m_threadContext.core->loadTemporarySave(m_threadContext.core, vf); + ok = m_threadContext.core->loadTemporarySave(m_threadContext.core, vf); } else { - m_threadContext.core->loadSave(m_threadContext.core, vf); + ok = m_threadContext.core->loadSave(m_threadContext.core, vf); + } + if (!ok) { + vf->close(vf); + } else { + m_savePath = path; } }); if (hasStarted()) { @@ -838,6 +878,7 @@ void CoreController::replaceGame(const QString& path) { } else { mCoreLoadFile(m_threadContext.core, fname.toUtf8().constData()); } + // TODO: Make sure updating the path is handled properly by everything that calls path() and baseDirectory() updateROMInfo(); } @@ -939,7 +980,7 @@ void CoreController::scanCard(const QString& path) { } } scanCards(lines); - m_eReaderData = eReaderData; + m_eReaderData = std::move(eReaderData); } else if (image.size() == QSize(989, 44) || image.size() == QSize(639, 44)) { const uchar* bits = image.constBits(); size_t size; @@ -1004,9 +1045,9 @@ void CoreController::attachPrinter() { } GB* gb = static_cast(m_threadContext.core->board); clearMultiplayerController(); - GBPrinterCreate(&m_printer.d); + GBPrinterCreate(&m_printer); m_printer.parent = this; - m_printer.d.print = [](GBPrinter* printer, int height, const uint8_t* data) { + m_printer.print = [](GBPrinter* printer, int height, const uint8_t* data) { QGBPrinter* qPrinter = reinterpret_cast(printer); QImage image(GB_VIDEO_HORIZONTAL_PIXELS, height, QImage::Format_Indexed8); QVector colors; @@ -1014,7 +1055,7 @@ void CoreController::attachPrinter() { colors.append(qRgb(0xA8, 0xA8, 0xA8)); colors.append(qRgb(0x50, 0x50, 0x50)); colors.append(qRgb(0x00, 0x00, 0x00)); - image.setColorTable(colors); + image.setColorTable(std::move(colors)); for (int y = 0; y < height; ++y) { for (int x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 4) { uint8_t byte = data[(x + y * GB_VIDEO_HORIZONTAL_PIXELS) / 4]; @@ -1027,7 +1068,7 @@ void CoreController::attachPrinter() { QMetaObject::invokeMethod(qPrinter->parent, "imagePrinted", Q_ARG(const QImage&, image)); }; Interrupter interrupter(this); - GBSIOSetDriver(&gb->sio, &m_printer.d.d); + GBSIOSetDriver(&gb->sio, &m_printer.d); } void CoreController::detachPrinter() { @@ -1036,7 +1077,7 @@ void CoreController::detachPrinter() { } Interrupter interrupter(this); GB* gb = static_cast(m_threadContext.core->board); - GBPrinterDonePrinting(&m_printer.d); + GBPrinterDonePrinting(&m_printer); GBSIOSetDriver(&gb->sio, nullptr); } @@ -1045,7 +1086,7 @@ void CoreController::endPrint() { return; } Interrupter interrupter(this); - GBPrinterDonePrinting(&m_printer.d); + GBPrinterDonePrinting(&m_printer); } #endif @@ -1189,7 +1230,7 @@ int CoreController::updateAutofire() { void CoreController::finishFrame() { if (!m_hwaccel) { unsigned width, height; - m_threadContext.core->desiredVideoDimensions(m_threadContext.core, &width, &height); + m_threadContext.core->currentVideoSize(m_threadContext.core, &width, &height); QMutexLocker locker(&m_bufferMutex); memcpy(m_completeBuffer.data(), m_activeBuffer.constData(), width * height * BYTES_PER_PIXEL); @@ -1216,11 +1257,7 @@ void CoreController::finishFrame() { } void CoreController::updatePlayerSave() { - int savePlayerId = 0; - mCoreConfigGetIntValue(&m_threadContext.core->config, "savePlayerId", &savePlayerId); - if (savePlayerId == 0 || m_multiplayer->attached() > 1) { - savePlayerId = m_multiplayer->playerId(this) + 1; - } + int savePlayerId = m_multiplayer->saveId(this); QString saveSuffix; if (savePlayerId < 2) { @@ -1231,7 +1268,11 @@ void CoreController::updatePlayerSave() { QByteArray saveSuffixBin(saveSuffix.toUtf8()); VFile* save = mDirectorySetOpenSuffix(&m_threadContext.core->dirs, m_threadContext.core->dirs.save, saveSuffixBin.constData(), O_CREAT | O_RDWR); if (save) { - m_threadContext.core->loadSave(m_threadContext.core, save); + if (!m_threadContext.core->loadSave(m_threadContext.core, save)) { + save->close(save); + } else { + m_savePath = QString::fromUtf8(m_threadContext.core->dirs.baseName) + saveSuffix; + } } } diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index e2cd03c12..c46b4d6e9 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -82,6 +82,11 @@ public: mCoreThread* thread() { return &m_threadContext; } + void setPath(const QString& path, const QString& base = {}); + QString path() const { return m_path; } + QString baseDirectory() const { return m_baseDirectory; } + QString savePath() const { return m_savePath; } + const color_t* drawContext(); QImage getPixels(); @@ -94,6 +99,7 @@ public: mPlatform platform() const; QSize screenDimensions() const; + unsigned videoScale() const; bool supportsFeature(Feature feature) const { return m_threadContext.core->supportsFeature(m_threadContext.core, static_cast(feature)); } bool hardwareAccelerated() const { return m_hwaccel; } @@ -102,8 +108,11 @@ public: mCheatDevice* cheatDevice() { return m_threadContext.core->cheatDevice(m_threadContext.core); } #ifdef USE_DEBUGGERS - mDebugger* debugger() { return m_threadContext.core->debugger; } - void setDebugger(mDebugger*); + mDebugger* debugger() { return &m_debugger; } + void attachDebugger(bool interrupt = true); + void detachDebugger(); + void attachDebuggerModule(mDebuggerModule*, bool interrupt = true); + void detachDebuggerModule(mDebuggerModule*); #endif void setMultiplayerController(MultiplayerController*); @@ -158,7 +167,7 @@ public slots: void saveBackupState(); void loadSave(const QString&, bool temporary); - void loadSave(VFile*, bool temporary); + void loadSave(VFile*, bool temporary, const QString& path = {}); void loadPatch(const QString&); void scanCard(const QString&); void scanCards(const QStringList&); @@ -245,6 +254,10 @@ private: CoreController* self; } m_logger{}; + QString m_path; + QString m_baseDirectory; + QString m_savePath; + bool m_patched = false; bool m_preload = false; @@ -292,6 +305,10 @@ private: bool m_autoload; int m_autosaveCounter = 0; +#ifdef USE_DEBUGGERS + struct mDebugger m_debugger; +#endif + int m_fastForward = false; int m_fastForwardForced = false; int m_fastForwardVolume = -1; @@ -313,8 +330,7 @@ private: VFile* m_vlVf = nullptr; #ifdef M_CORE_GB - struct QGBPrinter { - GBPrinter d; + struct QGBPrinter : public GBPrinter { CoreController* parent; } m_printer; #endif diff --git a/src/platform/qt/CoreManager.cpp b/src/platform/qt/CoreManager.cpp index cac1c2560..b2f7cabf0 100644 --- a/src/platform/qt/CoreManager.cpp +++ b/src/platform/qt/CoreManager.cpp @@ -16,6 +16,7 @@ #endif #include +#include #include using namespace QGBA; @@ -121,6 +122,7 @@ CoreController* CoreManager::loadGame(VFile* vf, const QString& path, const QStr if (m_multiplayer) { cc->setMultiplayerController(m_multiplayer); } + cc->setPath(path, info.dir().canonicalPath()); emit coreLoaded(cc); return cc; } @@ -161,7 +163,7 @@ CoreController* CoreManager::loadBIOS(int platform, const QString& path) { mCoreConfigSetOverrideIntValue(&core->config, "skipBios", 0); QByteArray bytes(info.baseName().toUtf8()); - strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName)); + strlcpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName)); bytes = info.dir().canonicalPath().toUtf8(); mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData())); @@ -170,6 +172,7 @@ CoreController* CoreManager::loadBIOS(int platform, const QString& path) { if (m_multiplayer) { cc->setMultiplayerController(m_multiplayer); } + cc->setPath(path, info.dir().canonicalPath()); emit coreLoaded(cc); return cc; } diff --git a/src/platform/qt/DebuggerConsole.h b/src/platform/qt/DebuggerConsole.h index f98635a68..fd2d4e952 100644 --- a/src/platform/qt/DebuggerConsole.h +++ b/src/platform/qt/DebuggerConsole.h @@ -25,7 +25,7 @@ protected: private: Ui::DebuggerConsole m_ui; - int m_historyOffset; + int m_historyOffset = 0; DebuggerConsoleController* m_consoleController; }; diff --git a/src/platform/qt/DebuggerConsoleController.cpp b/src/platform/qt/DebuggerConsoleController.cpp index 3a9446b15..dffd71bcf 100644 --- a/src/platform/qt/DebuggerConsoleController.cpp +++ b/src/platform/qt/DebuggerConsoleController.cpp @@ -19,26 +19,27 @@ using namespace QGBA; DebuggerConsoleController::DebuggerConsoleController(QObject* parent) : DebuggerController(&m_cliDebugger.d, parent) { - m_backend.d.printf = printf; - m_backend.d.init = init; - m_backend.d.deinit = deinit; - m_backend.d.readline = readLine; - m_backend.d.lineAppend = lineAppend; - m_backend.d.historyLast = historyLast; - m_backend.d.historyAppend = historyAppend; - m_backend.d.interrupt = interrupt; + m_backend.printf = printf; + m_backend.init = init; + m_backend.deinit = deinit; + m_backend.poll = poll; + m_backend.readline = readLine; + m_backend.lineAppend = lineAppend; + m_backend.historyLast = historyLast; + m_backend.historyAppend = historyAppend; + m_backend.interrupt = interrupt; m_backend.self = this; CLIDebuggerCreate(&m_cliDebugger); - CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d); + CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend); } void DebuggerConsoleController::enterLine(const QString& line) { CoreController::Interrupter interrupter(m_gameController); QMutexLocker lock(&m_mutex); m_lines.append(line); - if (m_cliDebugger.d.state == DEBUGGER_RUNNING) { - mDebuggerEnter(&m_cliDebugger.d, DEBUGGER_ENTER_MANUAL, nullptr); + if (m_cliDebugger.d.p && m_cliDebugger.d.p->state == DEBUGGER_RUNNING) { + mDebuggerEnter(m_cliDebugger.d.p, DEBUGGER_ENTER_MANUAL, nullptr); } m_cond.wakeOne(); } @@ -47,7 +48,7 @@ void DebuggerConsoleController::detach() { { CoreController::Interrupter interrupter(m_gameController); QMutexLocker lock(&m_mutex); - if (m_cliDebugger.d.state != DEBUGGER_SHUTDOWN) { + if (m_cliDebugger.d.p->state != DEBUGGER_SHUTDOWN) { m_lines.append(QString()); m_cond.wakeOne(); } @@ -60,7 +61,7 @@ void DebuggerConsoleController::attachInternal() { CoreController::Interrupter interrupter(m_gameController); QMutexLocker lock(&m_mutex); mCore* core = m_gameController->thread()->core; - CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend.d); + CLIDebuggerAttachBackend(&m_cliDebugger, &m_backend); CLIDebuggerAttachSystem(&m_cliDebugger, core->cliDebuggerSystem(core)); } @@ -82,12 +83,20 @@ void DebuggerConsoleController::init(struct CLIDebuggerBackend* be) { void DebuggerConsoleController::deinit(struct CLIDebuggerBackend* be) { Backend* consoleBe = reinterpret_cast(be); DebuggerConsoleController* self = consoleBe->self; - if (QThread::currentThread() == self->thread() && be->p->d.state != DEBUGGER_SHUTDOWN) { + if (QThread::currentThread() == self->thread() && be->p->d.p->state != DEBUGGER_SHUTDOWN) { self->m_lines.append(QString()); self->m_cond.wakeOne(); } } +int DebuggerConsoleController::poll(struct CLIDebuggerBackend* be, int32_t timeoutMs) { + Backend* consoleBe = reinterpret_cast(be); + DebuggerConsoleController* self = consoleBe->self; + QMutexLocker lock(&self->m_mutex); + self->m_cond.wait(&self->m_mutex, timeoutMs < 0 ? ULONG_MAX : static_cast(timeoutMs)); + return !self->m_lines.isEmpty(); +} + const char* DebuggerConsoleController::readLine(struct CLIDebuggerBackend* be, size_t* len) { Backend* consoleBe = reinterpret_cast(be); DebuggerConsoleController* self = consoleBe->self; @@ -137,10 +146,6 @@ void DebuggerConsoleController::interrupt(struct CLIDebuggerBackend* be) { DebuggerConsoleController* self = consoleBe->self; QMutexLocker lock(&self->m_mutex); self->m_cond.wakeOne(); - if (!self->m_lines.isEmpty()) { - return; - } - self->m_lines.append("\033"); } void DebuggerConsoleController::historyLoad() { @@ -162,7 +167,7 @@ void DebuggerConsoleController::historyLoad() { history.append(QString::fromUtf8(line)); } QMutexLocker lock(&m_mutex); - m_history = history; + m_history = std::move(history); } void DebuggerConsoleController::historySave() { diff --git a/src/platform/qt/DebuggerConsoleController.h b/src/platform/qt/DebuggerConsoleController.h index fdf183c08..b4530185b 100644 --- a/src/platform/qt/DebuggerConsoleController.h +++ b/src/platform/qt/DebuggerConsoleController.h @@ -42,6 +42,7 @@ private: static void printf(struct CLIDebuggerBackend* be, const char* fmt, ...); static void init(struct CLIDebuggerBackend* be); static void deinit(struct CLIDebuggerBackend* be); + static int poll(struct CLIDebuggerBackend* be, int32_t timeoutMs); static const char* readLine(struct CLIDebuggerBackend* be, size_t* len); static void lineAppend(struct CLIDebuggerBackend* be, const char* line); static const char* historyLast(struct CLIDebuggerBackend* be, size_t* len); @@ -56,8 +57,7 @@ private: QStringList m_lines; QByteArray m_last; - struct Backend { - CLIDebuggerBackend d; + struct Backend : public CLIDebuggerBackend { DebuggerConsoleController* self; } m_backend; }; diff --git a/src/platform/qt/DebuggerController.cpp b/src/platform/qt/DebuggerController.cpp index 7291b62fa..105549309 100644 --- a/src/platform/qt/DebuggerController.cpp +++ b/src/platform/qt/DebuggerController.cpp @@ -9,7 +9,7 @@ using namespace QGBA; -DebuggerController::DebuggerController(mDebugger* debugger, QObject* parent) +DebuggerController::DebuggerController(mDebuggerModule* debugger, QObject* parent) : QObject(parent) , m_debugger(debugger) { @@ -19,7 +19,7 @@ bool DebuggerController::isAttached() { if (!m_gameController) { return false; } - return m_gameController->debugger() == m_debugger; + return m_gameController->debugger() == m_debugger->p; } void DebuggerController::setController(std::shared_ptr controller) { @@ -45,7 +45,7 @@ void DebuggerController::attach() { } if (m_gameController) { attachInternal(); - m_gameController->setDebugger(m_debugger); + m_gameController->attachDebuggerModule(m_debugger); } else { m_autoattach = true; } @@ -58,7 +58,7 @@ void DebuggerController::detach() { if (m_gameController) { CoreController::Interrupter interrupter(m_gameController); shutdownInternal(); - m_gameController->setDebugger(nullptr); + m_gameController->detachDebuggerModule(m_debugger); } else { m_autoattach = false; } @@ -69,7 +69,7 @@ void DebuggerController::breakInto() { return; } CoreController::Interrupter interrupter(m_gameController); - mDebuggerEnter(m_debugger, DEBUGGER_ENTER_MANUAL, 0); + mDebuggerEnter(m_debugger->p, DEBUGGER_ENTER_MANUAL, 0); } void DebuggerController::shutdown() { diff --git a/src/platform/qt/DebuggerController.h b/src/platform/qt/DebuggerController.h index 45ac434da..722282f27 100644 --- a/src/platform/qt/DebuggerController.h +++ b/src/platform/qt/DebuggerController.h @@ -9,7 +9,7 @@ #include -struct mDebugger; +struct mDebuggerModule; namespace QGBA { @@ -19,7 +19,7 @@ class DebuggerController : public QObject { Q_OBJECT public: - DebuggerController(mDebugger* debugger, QObject* parent = nullptr); + DebuggerController(mDebuggerModule* debugger, QObject* parent = nullptr); public: bool isAttached(); @@ -35,7 +35,7 @@ protected: virtual void attachInternal(); virtual void shutdownInternal(); - mDebugger* const m_debugger; + mDebuggerModule* const m_debugger; std::shared_ptr m_gameController; private: diff --git a/src/platform/qt/Display.cpp b/src/platform/qt/Display.cpp index 7548e674c..8bec92f28 100644 --- a/src/platform/qt/Display.cpp +++ b/src/platform/qt/Display.cpp @@ -10,15 +10,17 @@ #include "DisplayGL.h" #include "DisplayQt.h" #include "LogController.h" +#include "VideoProxy.h" +#include "utils.h" #include using namespace QGBA; #if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) || defined(USE_EPOXY) -QGBA::Display::Driver Display::s_driver = QGBA::Display::Driver::OPENGL; +QGBA::Display::Driver QGBA::Display::s_driver = QGBA::Display::Driver::OPENGL; #else -QGBA::Display::Driver Display::s_driver = QGBA::Display::Driver::QT; +QGBA::Display::Driver QGBA::Display::s_driver = QGBA::Display::Driver::QT; #endif QGBA::Display* QGBA::Display::create(QWidget* parent) { @@ -111,10 +113,14 @@ void QGBA::Display::configure(ConfigController* config) { filter(opts->resampleVideo); config->updateOption("showOSD"); config->updateOption("showFrameCounter"); + config->updateOption("videoSync"); #if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(BUILD_GLES3) - if (opts->shader) { - struct VDir* shader = VDirOpen(opts->shader); - if (shader && supportsShaders()) { + if (opts->shader && supportsShaders()) { + struct VDir* shader = VDirOpenArchive(opts->shader); + if (!shader) { + shader = VDirOpen(opts->shader); + } + if (shader) { setShaders(shader); shader->close(shader); } @@ -122,6 +128,13 @@ void QGBA::Display::configure(ConfigController* config) { #endif } +VideoBackend* QGBA::Display::videoBackend() { + if (m_videoProxy) { + return m_videoProxy->backend(); + } + return nullptr; +} + void QGBA::Display::resizeEvent(QResizeEvent*) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) m_messagePainter.resize(size(), devicePixelRatioF()); @@ -169,3 +182,32 @@ void QGBA::Display::mouseMoveEvent(QMouseEvent*) { m_mouseTimer.stop(); m_mouseTimer.start(); } + +QPoint QGBA::Display::normalizedPoint(CoreController* controller, const QPoint& localRef) { + QSize screen(controller->screenDimensions()); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + QSize newSize((QSizeF(size()) * devicePixelRatioF()).toSize()); +#else + QSize newSize((QSizeF(size()) * devicePixelRatio()).toSize()); +#endif + + if (m_lockAspectRatio) { + QGBA::lockAspectRatio(screen, newSize); + } + + if (m_lockIntegerScaling) { + QGBA::lockIntegerScaling(screen, newSize); + } + + QPointF newPos(localRef); + newPos -= QPointF(width() / 2.0, height() / 2.0); + newPos = QPointF(newPos.x() * screen.width(), newPos.y() * screen.height()); + newPos = QPointF(newPos.x() / newSize.width(), newPos.y() / newSize.height()); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + newPos *= devicePixelRatioF(); +#else + newPos *= devicePixelRatio(); +#endif + newPos += QPointF(screen.width() / 2.0, screen.height() / 2.0); + return newPos.toPoint(); +} diff --git a/src/platform/qt/Display.h b/src/platform/qt/Display.h index af3cf7f00..ff6f0c23b 100644 --- a/src/platform/qt/Display.h +++ b/src/platform/qt/Display.h @@ -14,6 +14,7 @@ #include "MessagePainter.h" struct VDir; +struct VideoBackend; struct VideoShader; namespace QGBA { @@ -44,6 +45,8 @@ public: bool isShowOSD() const { return m_showOSD; } bool isShowFrameCounter() const { return m_showFrameCounter; } + QPoint normalizedPoint(CoreController*, const QPoint& localRef); + virtual void attach(std::shared_ptr); virtual void configure(ConfigController*); virtual void startDrawing(std::shared_ptr) = 0; @@ -52,9 +55,12 @@ public: virtual VideoShader* shaders() = 0; virtual int framebufferHandle() { return -1; } virtual void setVideoScale(int) {} + virtual void setBackgroundImage(const QImage&) = 0; + virtual QSize contentSize() const = 0; - virtual void setVideoProxy(std::shared_ptr proxy) { m_videoProxy = proxy; } + virtual void setVideoProxy(std::shared_ptr proxy) { m_videoProxy = std::move(proxy); } std::shared_ptr videoProxy() { return m_videoProxy; } + virtual VideoBackend* videoBackend(); signals: void drawingStarted(); @@ -72,6 +78,7 @@ public slots: virtual void showOSDMessages(bool enable); virtual void showFrameCounter(bool enable); virtual void filter(bool filter); + virtual void swapInterval(int interval) = 0; virtual void framePosted() = 0; virtual void setShaders(struct VDir*) = 0; virtual void clearShaders() = 0; diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 896f3acaf..e31437cad 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -9,14 +9,8 @@ #include #include +#include #include -#ifdef QT_OPENGL_ES_2 -#include -using QOpenGLFunctions_Baseline = QOpenGLFunctions_ES2; -#else -#include -using QOpenGLFunctions_Baseline = QOpenGLFunctions_3_2_Core; -#endif #include #include #include @@ -38,6 +32,21 @@ using QOpenGLFunctions_Baseline = QOpenGLFunctions_3_2_Core; #endif #endif +#ifdef _WIN32 +#include +#elif defined(Q_OS_MAC) +#include +#endif +#ifdef USE_GLX +#define GLX_GLXEXT_PROTOTYPES +typedef struct _XDisplay Display; +#include +#include +#endif +#ifdef USE_EGL +#include +#endif + #ifdef _WIN32 #define OVERHEAD_NSEC 1000000 #else @@ -45,6 +54,7 @@ using QOpenGLFunctions_Baseline = QOpenGLFunctions_3_2_Core; #endif #include "OpenGLBug.h" +#include "utils.h" using namespace QGBA; @@ -65,6 +75,10 @@ mGLWidget::mGLWidget(QWidget* parent) connect(&m_refresh, &QTimer::timeout, this, static_cast(&QWidget::update)); } +mGLWidget::~mGLWidget() { + // This is needed for unique_ptr to work +} + void mGLWidget::initializeGL() { m_vao = std::make_unique(); m_vao->create(); @@ -94,13 +108,15 @@ void mGLWidget::initializeGL() { m_vaoDone = false; m_tex = 0; + + m_paintDev = std::make_unique(); } bool mGLWidget::finalizeVAO() { if (!context() || !m_vao) { return false; } - QOpenGLFunctions_Baseline* fn = context()->versionFunctions(); + QOpenGLExtraFunctions* fn = context()->extraFunctions(); if (!fn) { return false; } @@ -128,7 +144,7 @@ void mGLWidget::paintGL() { m_refresh.start(10); return; } - QOpenGLFunctions_Baseline* fn = context()->versionFunctions(); + QOpenGLExtraFunctions* fn = context()->extraFunctions(); m_program->bind(); m_vao->bind(); fn->glBindTexture(GL_TEXTURE_2D, m_tex); @@ -145,6 +161,23 @@ void mGLWidget::paintGL() { } else { m_refresh.start(17); } + + if (m_showOSD && m_messagePainter) { + qreal r = window()->devicePixelRatio(); + m_paintDev->setDevicePixelRatio(r); + m_paintDev->setSize(size() * r); + QPainter painter(m_paintDev.get()); + m_messagePainter->paint(&painter); + painter.end(); + } +} + +void mGLWidget::setMessagePainter(MessagePainter* messagePainter) { + m_messagePainter = messagePainter; +} + +void mGLWidget::setShowOSD(bool showOSD) { + m_showOSD = showOSD; } DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent) @@ -152,6 +185,7 @@ DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent) { setAttribute(Qt::WA_NativeWindow); window()->windowHandle()->setFormat(format); + windowHandle()->setSurfaceType(QSurface::OpenGLSurface); windowHandle()->create(); #ifdef USE_SHARE_WIDGET @@ -165,6 +199,7 @@ DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent) m_gl = new mGLWidget; m_gl->setAttribute(Qt::WA_NativeWindow); m_gl->setFormat(format); + m_gl->setMessagePainter(messagePainter()); QBoxLayout* layout = new QVBoxLayout; layout->addWidget(m_gl); layout->setContentsMargins(0, 0, 0, 0); @@ -177,11 +212,6 @@ DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent) m_drawThread.setObjectName("Painter Thread"); m_painter->setThread(&m_drawThread); - m_proxyThread.setObjectName("OpenGL Proxy Thread"); - m_proxyContext = std::make_unique(); - m_proxyContext->setFormat(format); - connect(m_painter.get(), &PainterGL::created, this, &DisplayGL::setupProxyThread); - connect(&m_drawThread, &QThread::started, m_painter.get(), &PainterGL::create); connect(m_painter.get(), &PainterGL::started, this, [this] { m_hasStarted = true; @@ -196,11 +226,6 @@ DisplayGL::~DisplayGL() { QMetaObject::invokeMethod(m_painter.get(), "destroy", Qt::BlockingQueuedConnection); m_drawThread.exit(); m_drawThread.wait(); - - if (m_proxyThread.isRunning()) { - m_proxyThread.exit(); - m_proxyThread.wait(); - } } bool DisplayGL::supportsShaders() const { @@ -220,7 +245,10 @@ void DisplayGL::startDrawing(std::shared_ptr controller) { m_isDrawing = true; m_painter->setContext(controller); m_painter->setMessagePainter(messagePainter()); - m_context = controller; + m_context = std::move(controller); + if (videoProxy()) { + videoProxy()->moveToThread(&m_drawThread); + } lockAspectRatio(isAspectRatioLocked()); lockIntegerScaling(isIntegerScalingLocked()); @@ -235,7 +263,7 @@ void DisplayGL::startDrawing(std::shared_ptr controller) { messagePainter()->resize(size(), devicePixelRatio()); #endif - CoreController::Interrupter interrupter(controller); + CoreController::Interrupter interrupter(m_context); QMetaObject::invokeMethod(m_painter.get(), "start"); if (!m_gl) { if (shouldDisableUpdates()) { @@ -245,6 +273,8 @@ void DisplayGL::startDrawing(std::shared_ptr controller) { show(); m_gl->reset(); } + + QTimer::singleShot(8, this, &DisplayGL::updateContentSize); } bool DisplayGL::supportsFormat(const QSurfaceFormat& format) { @@ -331,12 +361,14 @@ void DisplayGL::unpauseDrawing() { if (!m_gl && shouldDisableUpdates()) { setUpdatesEnabled(false); } + QMetaObject::invokeMethod(this, "updateContentSize", Qt::QueuedConnection); } } void DisplayGL::forceDraw() { if (m_hasStarted) { QMetaObject::invokeMethod(m_painter.get(), "forceDraw"); + QMetaObject::invokeMethod(this, "updateContentSize", Qt::QueuedConnection); } } @@ -357,6 +389,9 @@ void DisplayGL::interframeBlending(bool enable) { void DisplayGL::showOSDMessages(bool enable) { Display::showOSDMessages(enable); + if (m_gl) { + m_gl->setShowOSD(enable); + } QMetaObject::invokeMethod(m_painter.get(), "showOSD", Q_ARG(bool, enable)); } @@ -370,6 +405,10 @@ void DisplayGL::filter(bool filter) { QMetaObject::invokeMethod(m_painter.get(), "filter", Q_ARG(bool, filter)); } +void DisplayGL::swapInterval(int interval) { + QMetaObject::invokeMethod(m_painter.get(), "swapInterval", Q_ARG(int, interval)); +} + void DisplayGL::framePosted() { m_painter->enqueue(m_context->drawContext()); QMetaObject::invokeMethod(m_painter.get(), "draw"); @@ -396,6 +435,11 @@ void DisplayGL::setVideoScale(int scale) { QMetaObject::invokeMethod(m_painter.get(), "resizeContext"); } +void DisplayGL::setBackgroundImage(const QImage& image) { + QMetaObject::invokeMethod(m_painter.get(), "setBackgroundImage", Q_ARG(const QImage&, image)); + QMetaObject::invokeMethod(this, "updateContentSize", Qt::QueuedConnection); +} + void DisplayGL::resizeEvent(QResizeEvent* event) { Display::resizeEvent(event); resizePainter(); @@ -420,32 +464,13 @@ bool DisplayGL::shouldDisableUpdates() { void DisplayGL::setVideoProxy(std::shared_ptr proxy) { Display::setVideoProxy(proxy); if (proxy) { - proxy->moveToThread(&m_proxyThread); + proxy->moveToThread(&m_drawThread); } - m_painter->setVideoProxy(proxy); + m_painter->setVideoProxy(std::move(proxy)); } -void DisplayGL::setupProxyThread() { - m_proxyContext->moveToThread(&m_proxyThread); - m_proxySurface.create(); - connect(&m_proxyThread, &QThread::started, m_proxyContext.get(), [this]() { - m_proxyContext->setShareContext(m_painter->shareContext()); - m_proxyContext->create(); - m_proxyContext->makeCurrent(&m_proxySurface); -#if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); -#endif - }); - connect(m_painter.get(), &PainterGL::texSwapped, m_proxyContext.get(), [this]() { - if (!m_context->hardwareAccelerated()) { - return; - } - if (videoProxy()) { - videoProxy()->processData(); - } - m_painter->updateFramebufferHandle(); - }, Qt::BlockingQueuedConnection); - m_proxyThread.start(); +void DisplayGL::updateContentSize() { + QMetaObject::invokeMethod(m_painter.get(), "contentSize", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QSize, m_cachedContentSize)); } int DisplayGL::framebufferHandle() { @@ -509,19 +534,15 @@ void PainterGL::create() { mGLES2Context* gl2Backend; #endif - m_paintDev = std::make_unique(); + if (!m_widget) { + m_paintDev = std::make_unique(); + } #if defined(BUILD_GLES2) || defined(BUILD_GLES3) if (m_supportsShaders) { - QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions(); gl2Backend = static_cast(malloc(sizeof(mGLES2Context))); mGLES2ContextCreate(gl2Backend); m_backend = &gl2Backend->d; - fn->glGenTextures(m_bridgeTexes.size(), m_bridgeTexes.data()); - for (auto tex : m_bridgeTexes) { - m_freeTex.enqueue(tex); - } - m_bridgeTexIn = m_freeTex.dequeue(); } #endif @@ -543,7 +564,7 @@ void PainterGL::create() { #if defined(BUILD_GLES2) || defined(BUILD_GLES3) mGLES2Context* gl2Backend = reinterpret_cast(painter->m_backend); if (painter->m_widget && painter->supportsShaders()) { - QOpenGLFunctions_Baseline* fn = painter->m_gl->versionFunctions(); + QOpenGLFunctions* fn = painter->m_gl->functions(); fn->glFinish(); painter->m_widget->setTex(painter->m_finalTex[painter->m_finalTexIdx]); painter->m_finalTexIdx ^= 1; @@ -589,11 +610,9 @@ void PainterGL::destroy() { } makeCurrent(); #if defined(BUILD_GLES2) || defined(BUILD_GLES3) - QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions(); if (m_shader.passes) { mGLES2ShaderFree(&m_shader); } - fn->glDeleteTextures(m_bridgeTexes.size(), m_bridgeTexes.data()); #endif m_backend->deinit(m_backend); m_gl->doneCurrent(); @@ -605,7 +624,7 @@ void PainterGL::destroy() { } void PainterGL::setContext(std::shared_ptr context) { - m_context = context; + m_context = std::move(context); } void PainterGL::resizeContext() { @@ -624,18 +643,31 @@ void PainterGL::resizeContext() { return; } dequeueAll(false); - m_backend->setDimensions(m_backend, size.width(), size.height()); + + mRectangle dims = {0, 0, size.width(), size.height()}; + m_backend->setLayerDimensions(m_backend, VIDEO_LAYER_IMAGE, &dims); + recenterLayers(); + m_dims = size; } void PainterGL::setMessagePainter(MessagePainter* messagePainter) { m_messagePainter = messagePainter; } +void PainterGL::recenterLayers() { + if (!m_context) { + return; + } + VideoBackendRecenter(m_backend, std::max(1U, m_context->videoScale())); +} + void PainterGL::resize(const QSize& size) { qreal r = m_window->devicePixelRatio(); m_size = size; - m_paintDev->setSize(m_size * r); - m_paintDev->setDevicePixelRatio(r); + if (m_paintDev) { + m_paintDev->setSize(m_size * r); + m_paintDev->setDevicePixelRatio(r); + } if (m_started && !m_active) { forceDraw(); } @@ -670,6 +702,32 @@ void PainterGL::filter(bool filter) { } } +void PainterGL::swapInterval(int interval) { + if (!m_started) { + return; + } + m_swapInterval = interval; +#ifdef Q_OS_WIN + wglSwapIntervalEXT(interval); +#elif defined(Q_OS_MAC) + CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &interval); +#else +#ifdef USE_GLX + if (QGuiApplication::platformName() == "xcb") { + ::Display* display = glXGetCurrentDisplay(); + GLXDrawable drawable = glXGetCurrentDrawable(); + glXSwapIntervalEXT(display, drawable, interval); + } +#endif +#ifdef USE_EGL + if (QGuiApplication::platformName().contains("egl") || QGuiApplication::platformName() == "wayland") { + EGLDisplay display = eglGetCurrentDisplay(); + eglSwapInterval(display, interval); + } +#endif +#endif +} + #ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #endif @@ -680,7 +738,7 @@ void PainterGL::start() { if (glContextHasBug(OpenGLBug::GLTHREAD_BLOCKS_SWAP)) { // Suggested on Discord as a way to strongly hint that glthread should be disabled // See https://gitlab.freedesktop.org/mesa/mesa/-/issues/8035 - QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions(); + QOpenGLFunctions* fn = m_gl->functions(); fn->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); } #endif @@ -691,16 +749,16 @@ void PainterGL::start() { } #endif resizeContext(); - m_context->addFrameAction(std::bind(&PainterGL::swapTex, this)); m_buffer = nullptr; m_active = true; m_started = true; + swapInterval(1); emit started(); } void PainterGL::draw() { - if (!m_started || (m_queue.isEmpty() && m_queueTex.isEmpty())) { + if (!m_started || m_queue.isEmpty()) { return; } @@ -726,12 +784,16 @@ void PainterGL::draw() { } return; } + int wantSwap = sync->audioWait || sync->videoFrameWait; + if (m_swapInterval != wantSwap) { + swapInterval(wantSwap); + } dequeue(); bool forceRedraw = true; if (!m_delayTimer.isValid()) { m_delayTimer.start(); } else { - if (sync->audioWait || sync->videoFrameWait) { + if (wantSwap) { while (m_delayTimer.nsecsElapsed() + OVERHEAD_NSEC < 1000000000 / sync->fpsTarget) { QThread::usleep(500); } @@ -783,6 +845,11 @@ void PainterGL::doStop() { } m_backend->clear(m_backend); m_backend->swap(m_backend); + if (m_videoProxy) { + m_videoProxy->reset(); + m_videoProxy->moveToThread(m_window->thread()); + m_videoProxy.reset(); + } } void PainterGL::pause() { @@ -797,12 +864,12 @@ void PainterGL::unpause() { void PainterGL::performDraw() { float r = m_window->devicePixelRatio(); - m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r); + m_backend->contextResized(m_backend, m_size.width() * r, m_size.height() * r); if (m_buffer) { - m_backend->postFrame(m_backend, m_buffer); + m_backend->setImage(m_backend, VIDEO_LAYER_IMAGE, m_buffer); } m_backend->drawFrame(m_backend); - if (m_showOSD && m_messagePainter) { + if (m_showOSD && m_messagePainter && m_paintDev && !glContextHasBug(OpenGLBug::IG4ICD_CRASH)) { m_painter.begin(m_paintDev.get()); m_messagePainter->paint(&m_painter); m_painter.end(); @@ -810,33 +877,22 @@ void PainterGL::performDraw() { } void PainterGL::enqueue(const uint32_t* backing) { - if (!backing) { - return; - } QMutexLocker locker(&m_mutex); uint32_t* buffer = nullptr; - if (m_free.isEmpty()) { - buffer = m_queue.dequeue(); - } else { - buffer = m_free.takeLast(); - } - if (buffer) { - QSize size = m_context->screenDimensions(); - memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL); + if (backing) { + if (m_free.isEmpty()) { + buffer = m_queue.dequeue(); + } else { + buffer = m_free.takeLast(); + } + if (buffer) { + QSize size = m_context->screenDimensions(); + memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL); + } } m_queue.enqueue(buffer); } -void PainterGL::enqueue(GLuint tex) { - QMutexLocker locker(&m_mutex); - if (m_freeTex.isEmpty()) { - m_bridgeTexIn = m_queueTex.dequeue(); - } else { - m_bridgeTexIn = m_freeTex.takeLast(); - } - m_queueTex.enqueue(tex); -} - void PainterGL::dequeue() { QMutexLocker locker(&m_mutex); if (!m_queue.isEmpty()) { @@ -846,19 +902,6 @@ void PainterGL::dequeue() { } m_buffer = buffer; } - - if (!m_queueTex.isEmpty()) { - if (m_bridgeTexOut != std::numeric_limits::max()) { - m_freeTex.enqueue(m_bridgeTexOut); - } - m_bridgeTexOut = m_queueTex.dequeue(); -#if defined(BUILD_GLES2) || defined(BUILD_GLES3) - if (supportsShaders()) { - mGLES2Context* gl2Backend = reinterpret_cast(m_backend); - gl2Backend->tex = m_bridgeTexOut; - } -#endif - } } void PainterGL::dequeueAll(bool keep) { @@ -879,23 +922,13 @@ void PainterGL::dequeueAll(bool keep) { m_free.append(m_buffer); m_buffer = nullptr; } - - m_queueTex.clear(); - m_freeTex.clear(); - for (auto tex : m_bridgeTexes) { - if (keep && tex == m_bridgeTexIn) { - continue; - } - m_freeTex.enqueue(tex); - } - if (!keep) { - m_bridgeTexIn = m_freeTex.dequeue(); - m_bridgeTexOut = std::numeric_limits::max(); - } } void PainterGL::setVideoProxy(std::shared_ptr proxy) { m_videoProxy = proxy; + if (proxy) { + proxy->setProxiedBackend(m_backend); + } } void PainterGL::interrupt() { @@ -915,8 +948,9 @@ void PainterGL::setShaders(struct VDir* dir) { mGLES2ShaderDetach(reinterpret_cast(m_backend)); mGLES2ShaderFree(&m_shader); } - mGLES2ShaderLoad(&m_shader, dir); - mGLES2ShaderAttach(reinterpret_cast(m_backend), static_cast(m_shader.passes), m_shader.nPasses); + if (mGLES2ShaderLoad(&m_shader, dir)) { + mGLES2ShaderAttach(reinterpret_cast(m_backend), static_cast(m_shader.passes), m_shader.nPasses); + } if (!m_started) { m_gl->doneCurrent(); @@ -948,11 +982,18 @@ VideoShader* PainterGL::shaders() { return &m_shader; } +QSize PainterGL::contentSize() const { + unsigned width, height; + VideoBackendGetFrameSize(m_backend, &width, &height); + return {saturateCast(width), + saturateCast(height)}; +} + int PainterGL::glTex() { #if defined(BUILD_GLES2) || defined(BUILD_GLES3) if (supportsShaders()) { mGLES2Context* gl2Backend = reinterpret_cast(m_backend); - return gl2Backend->tex; + return gl2Backend->tex[VIDEO_LAYER_IMAGE]; } #endif #ifdef BUILD_GL @@ -971,31 +1012,25 @@ QOpenGLContext* PainterGL::shareContext() { } } -void PainterGL::updateFramebufferHandle() { - QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions(); - // TODO: Figure out why glFlush doesn't work here on Intel/Windows - if (glContextHasBug(OpenGLBug::CROSS_THREAD_FLUSH)) { - fn->glFinish(); - } else { - fn->glFlush(); - } - - CoreController::Interrupter interrupter(m_context); - if (!m_context->hardwareAccelerated()) { - return; - } - enqueue(m_bridgeTexIn); - m_context->setFramebufferHandle(m_bridgeTexIn); -} - -void PainterGL::swapTex() { +void PainterGL::setBackgroundImage(const QImage& image) { if (!m_started) { - return; + makeCurrent(); } - CoreController::Interrupter interrupter(m_context); - emit texSwapped(); - m_context->addFrameAction(std::bind(&PainterGL::swapTex, this)); + m_backend->setImageSize(m_backend, VIDEO_LAYER_BACKGROUND, image.width(), image.height()); + recenterLayers(); + + if (!image.isNull()) { + m_background = image.convertToFormat(QImage::Format_RGB32); + m_background = m_background.rgbSwapped(); + m_backend->setImage(m_backend, VIDEO_LAYER_BACKGROUND, m_background.constBits()); + } else { + m_background = QImage(); + } + + if (!m_started) { + m_gl->doneCurrent(); + } } #endif diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index 3ed31a9d8..d94a68621 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -37,7 +37,7 @@ #include "CoreController.h" #include "VideoProxy.h" -#include "platform/video-backend.h" +#include class QOpenGLPaintDevice; class QOpenGLWidget; @@ -51,9 +51,12 @@ Q_OBJECT public: mGLWidget(QWidget* parent = nullptr); + ~mGLWidget(); void setTex(GLuint tex) { m_tex = tex; } void setVBO(GLuint vbo) { m_vbo = vbo; } + void setMessagePainter(MessagePainter*); + void setShowOSD(bool showOSD); bool finalizeVAO(); void reset(); @@ -72,6 +75,9 @@ private: QTimer m_refresh; int m_refreshResidue = 0; + std::unique_ptr m_paintDev; + MessagePainter* m_messagePainter = nullptr; + bool m_showOSD = false; }; class PainterGL; @@ -88,6 +94,7 @@ public: VideoShader* shaders() override; void setVideoProxy(std::shared_ptr) override; int framebufferHandle() override; + QSize contentSize() const override { return m_cachedContentSize; } static bool supportsFormat(const QSurfaceFormat&); @@ -102,18 +109,20 @@ public slots: void showOSDMessages(bool enable) override; void showFrameCounter(bool enable) override; void filter(bool filter) override; + void swapInterval(int interval) override; void framePosted() override; void setShaders(struct VDir*) override; void clearShaders() override; void resizeContext() override; void setVideoScale(int scale) override; + void setBackgroundImage(const QImage&) override; protected: virtual void paintEvent(QPaintEvent*) override { forceDraw(); } virtual void resizeEvent(QResizeEvent*) override; private slots: - void setupProxyThread(); + void updateContentSize(); private: void resizePainter(); @@ -125,11 +134,9 @@ private: bool m_hasStarted = false; std::unique_ptr m_painter; QThread m_drawThread; - QThread m_proxyThread; std::shared_ptr m_context; mGLWidget* m_gl; - QOffscreenSurface m_proxySurface; - std::unique_ptr m_proxyContext; + QSize m_cachedContentSize; }; class PainterGL : public QObject { @@ -143,7 +150,6 @@ public: void setContext(std::shared_ptr); void setMessagePainter(MessagePainter*); void enqueue(const uint32_t* backing); - void enqueue(GLuint tex); void stop(); @@ -155,9 +161,6 @@ public: void setVideoProxy(std::shared_ptr); void interrupt(); - // Run on main thread - void swapTex(); - public slots: void create(); void destroy(); @@ -174,12 +177,14 @@ public slots: void showOSD(bool enable); void showFrameCounter(bool enable); void filter(bool filter); + void swapInterval(int interval); void resizeContext(); - void updateFramebufferHandle(); + void setBackgroundImage(const QImage&); void setShaders(struct VDir*); void clearShaders(); VideoShader* shaders(); + QSize contentSize() const; signals: void created(); @@ -194,24 +199,19 @@ private: void performDraw(); void dequeue(); void dequeueAll(bool keep = false); + void recenterLayers(); std::array, 3> m_buffers; QList m_free; QQueue m_queue; uint32_t* m_buffer = nullptr; - std::array m_bridgeTexes; - QQueue m_freeTex; - QQueue m_queueTex; - - GLuint m_bridgeTexIn = std::numeric_limits::max(); - GLuint m_bridgeTexOut = std::numeric_limits::max(); - QPainter m_painter; QMutex m_mutex; QWindow* m_window; QSurface* m_surface; QSurfaceFormat m_format; + QImage m_background; std::unique_ptr m_paintDev; std::unique_ptr m_gl; int m_finalTexIdx = 0; @@ -232,6 +232,7 @@ private: MessagePainter* m_messagePainter = nullptr; QElapsedTimer m_delayTimer; std::shared_ptr m_videoProxy; + int m_swapInterval = -1; }; } diff --git a/src/platform/qt/DisplayQt.cpp b/src/platform/qt/DisplayQt.cpp index 20ec44f0d..1d9efebec 100644 --- a/src/platform/qt/DisplayQt.cpp +++ b/src/platform/qt/DisplayQt.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 @@ -19,16 +19,31 @@ using namespace QGBA; DisplayQt::DisplayQt(QWidget* parent) : Display(parent) { + m_backend.init = &DisplayQt::init; + m_backend.deinit = &DisplayQt::deinit; + m_backend.setLayerDimensions = &DisplayQt::setLayerDimensions; + m_backend.layerDimensions = &DisplayQt::layerDimensions; + m_backend.swap = &DisplayQt::swap; + m_backend.clear = &DisplayQt::clear; + m_backend.contextResized = &DisplayQt::contextResized; + m_backend.setImageSize = &DisplayQt::setImageSize; + m_backend.imageSize = &DisplayQt::imageSize; + m_backend.setImage = &DisplayQt::setImage; + m_backend.drawFrame = &DisplayQt::drawFrame; + m_backend.filter = isFiltered(); + m_backend.lockAspectRatio = isAspectRatioLocked(); + m_backend.lockIntegerScaling = isIntegerScalingLocked(); + m_backend.interframeBlending = hasInterframeBlending(); + m_backend.user = this; } void DisplayQt::startDrawing(std::shared_ptr controller) { QSize size = controller->screenDimensions(); m_width = size.width(); m_height = size.height(); - m_backing = QImage(); m_oldBacking = QImage(); m_isDrawing = true; - m_context = controller; + m_context = std::move(controller); emit drawingStarted(); } @@ -39,44 +54,51 @@ void DisplayQt::stopDrawing() { void DisplayQt::lockAspectRatio(bool lock) { Display::lockAspectRatio(lock); + m_backend.lockAspectRatio = lock; update(); } void DisplayQt::lockIntegerScaling(bool lock) { Display::lockIntegerScaling(lock); + m_backend.lockIntegerScaling = lock; update(); } void DisplayQt::interframeBlending(bool lock) { Display::interframeBlending(lock); + m_backend.interframeBlending = lock; update(); } void DisplayQt::filter(bool filter) { Display::filter(filter); + m_backend.filter = filter; update(); } void DisplayQt::framePosted() { update(); const color_t* buffer = m_context->drawContext(); - if (const_cast(m_backing).bits() == reinterpret_cast(buffer)) { + if (const_cast(m_layers[VIDEO_LAYER_IMAGE]).bits() == reinterpret_cast(buffer)) { return; } - m_oldBacking = m_backing; + m_oldBacking = m_layers[VIDEO_LAYER_IMAGE]; #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 - m_backing = QImage(reinterpret_cast(buffer), m_width, m_height, QImage::Format_RGB16); + m_layers[VIDEO_LAYER_IMAGE] = QImage(reinterpret_cast(buffer), m_width, m_height, QImage::Format_RGB16); #else - m_backing = QImage(reinterpret_cast(buffer), m_width, m_height, QImage::Format_RGB555); + m_layers[VIDEO_LAYER_IMAGE] = QImage(reinterpret_cast(buffer), m_width, m_height, QImage::Format_RGB555); #endif #else - m_backing = QImage(reinterpret_cast(buffer), m_width, m_height, QImage::Format_ARGB32); - m_backing = m_backing.convertToFormat(QImage::Format_RGB32); + m_layers[VIDEO_LAYER_IMAGE] = QImage(reinterpret_cast(buffer), m_width, m_height, QImage::Format_ARGB32); + m_layers[VIDEO_LAYER_IMAGE] = m_layers[VIDEO_LAYER_IMAGE].convertToFormat(QImage::Format_RGB32); #endif #ifndef COLOR_5_6_5 - m_backing = m_backing.rgbSwapped(); + m_layers[VIDEO_LAYER_IMAGE] = m_layers[VIDEO_LAYER_IMAGE].rgbSwapped(); #endif + m_layerDims[VIDEO_LAYER_IMAGE].setWidth(m_width); + m_layerDims[VIDEO_LAYER_IMAGE].setHeight(m_height); + redoBounds(); } void DisplayQt::resizeContext() { @@ -88,25 +110,141 @@ void DisplayQt::resizeContext() { m_width = size.width(); m_height = size.height(); m_oldBacking = QImage(); - m_backing = QImage(); + m_layers[VIDEO_LAYER_IMAGE] = QImage(); } } +void DisplayQt::setBackgroundImage(const QImage& image) { + m_layers[VIDEO_LAYER_BACKGROUND] = image; + redoBounds(); + update(); +} + void DisplayQt::paintEvent(QPaintEvent*) { QPainter painter(this); painter.fillRect(QRect(QPoint(), size()), Qt::black); if (isFiltered()) { painter.setRenderHint(QPainter::SmoothPixmapTransform); } - QRect full(clampSize(QSize(m_width, m_height), size(), isAspectRatioLocked(), isIntegerScalingLocked())); + + struct mRectangle frame; + VideoBackendGetFrame(&m_backend, &frame); + QPoint origin(-frame.x, -frame.y); + QRect full(clampSize(contentSize(), size(), isAspectRatioLocked(), isIntegerScalingLocked())); + painter.save(); + painter.translate(full.topLeft()); + painter.scale(full.width() / static_cast(frame.width), full.height() / static_cast(frame.height)); + + if (!m_layers[VIDEO_LAYER_BACKGROUND].isNull()) { + painter.drawImage(m_layerDims[VIDEO_LAYER_BACKGROUND].translated(origin), m_layers[VIDEO_LAYER_BACKGROUND]); + } if (hasInterframeBlending()) { - painter.drawImage(full, m_oldBacking, QRect(0, 0, m_width, m_height)); + painter.drawImage(m_layerDims[VIDEO_LAYER_IMAGE].translated(origin), m_oldBacking, QRect(0, 0, m_width, m_height)); painter.setOpacity(0.5); } - painter.drawImage(full, m_backing, QRect(0, 0, m_width, m_height)); + painter.drawImage(m_layerDims[VIDEO_LAYER_IMAGE].translated(origin), m_layers[VIDEO_LAYER_IMAGE], QRect(0, 0, m_width, m_height)); + + for (int i = VIDEO_LAYER_IMAGE + 1; i < VIDEO_LAYER_MAX; ++i) { + if (m_layers[i].isNull()) { + continue; + } + + painter.drawImage(m_layerDims[i].translated(origin), m_layers[i]); + } + + painter.restore(); painter.setOpacity(1); if (isShowOSD() || isShowFrameCounter()) { messagePainter()->paint(&painter); } } + +void DisplayQt::redoBounds() { + const static std::initializer_list centeredLayers{VIDEO_LAYER_BACKGROUND}; + mRectangle frame = {0}; + frame.width = m_width; + frame.height = m_height; + + for (VideoLayer l : centeredLayers) { + mRectangle dims{}; + dims.width = m_layers[l].width(); + dims.height = m_layers[l].height(); + mRectangleCenter(&frame, &dims); + m_layerDims[l].setX(dims.x); + m_layerDims[l].setY(dims.y); + m_layerDims[l].setWidth(dims.width); + m_layerDims[l].setHeight(dims.height); + } +} + +QSize DisplayQt::contentSize() const { + unsigned w, h; + VideoBackendGetFrameSize(&m_backend, &w, &h); + return {saturateCast(w), saturateCast(h)}; +} + +void DisplayQt::init(struct VideoBackend*, WHandle) { +} + +void DisplayQt::deinit(struct VideoBackend*) { +} + +void DisplayQt::setLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct mRectangle* dims) { + DisplayQt* self = static_cast(v->user); + if (layer > self->m_layerDims.size()) { + return; + } + self->m_layerDims[layer] = QRect(dims->x, dims->y, dims->width, dims->height); +} + +void DisplayQt::layerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct mRectangle* dims) { + DisplayQt* self = static_cast(v->user); + if (layer > self->m_layerDims.size()) { + return; + } + QRect rect = self->m_layerDims[layer]; + dims->x = rect.x(); + dims->y = rect.y(); + dims->width = rect.width(); + dims->height = rect.height(); +} + +void DisplayQt::swap(struct VideoBackend*) { +} + +void DisplayQt::clear(struct VideoBackend*) { +} + +void DisplayQt::contextResized(struct VideoBackend*, unsigned, unsigned) { +} + +void DisplayQt::setImageSize(struct VideoBackend* v, enum VideoLayer layer, int w, int h) { + DisplayQt* self = static_cast(v->user); + if (layer > self->m_layers.size()) { + return; + } + self->m_layers[layer] = QImage(w, h, QImage::Format_ARGB32); +} + +void DisplayQt::imageSize(struct VideoBackend* v, enum VideoLayer layer, int* w, int* h) { + DisplayQt* self = static_cast(v->user); + if (layer > self->m_layers.size()) { + return; + } + *w = self->m_layers[layer].width(); + *h = self->m_layers[layer].height(); +} + +void DisplayQt::setImage(struct VideoBackend* v, enum VideoLayer layer, const void* frame) { + DisplayQt* self = static_cast(v->user); + if (layer > self->m_layers.size()) { + return; + } + QImage& image = self->m_layers[layer]; + self->m_layers[layer] = QImage(static_cast(frame), image.width(), image.height(), QImage::Format_ARGB32).rgbSwapped(); +} + +void DisplayQt::drawFrame(struct VideoBackend* v) { + QMetaObject::invokeMethod(static_cast(v->user), "update"); +} diff --git a/src/platform/qt/DisplayQt.h b/src/platform/qt/DisplayQt.h index e8623468f..c1363dede 100644 --- a/src/platform/qt/DisplayQt.h +++ b/src/platform/qt/DisplayQt.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 @@ -10,6 +10,9 @@ #include #include +#include +#include + namespace QGBA { class DisplayQt : public Display { @@ -22,6 +25,8 @@ public: bool isDrawing() const override { return m_isDrawing; } bool supportsShaders() const override { return false; } VideoShader* shaders() override { return nullptr; } + QSize contentSize() const override; + VideoBackend* videoBackend() override { return &m_backend; } public slots: void stopDrawing() override; @@ -31,20 +36,38 @@ public slots: void lockAspectRatio(bool lock) override; void lockIntegerScaling(bool lock) override; void interframeBlending(bool enable) override; + void swapInterval(int) override {}; void filter(bool filter) override; void framePosted() override; void setShaders(struct VDir*) override {} void clearShaders() override {} void resizeContext() override; + void setBackgroundImage(const QImage&) override; protected: virtual void paintEvent(QPaintEvent*) override; private: + void redoBounds(); + + static void init(struct VideoBackend*, WHandle); + static void deinit(struct VideoBackend*); + static void setLayerDimensions(struct VideoBackend*, enum VideoLayer, const struct mRectangle*); + static void layerDimensions(const struct VideoBackend*, enum VideoLayer, struct mRectangle*); + static void swap(struct VideoBackend*); + static void clear(struct VideoBackend*); + static void contextResized(struct VideoBackend*, unsigned w, unsigned h); + static void setImageSize(struct VideoBackend*, enum VideoLayer, int w, int h); + static void imageSize(struct VideoBackend*, enum VideoLayer, int* w, int* h); + static void setImage(struct VideoBackend*, enum VideoLayer, const void* frame); + static void drawFrame(struct VideoBackend*); + + VideoBackend m_backend{}; + std::array m_layerDims; + std::array m_layers; bool m_isDrawing = false; - int m_width; - int m_height; - QImage m_backing{nullptr}; + int m_width = -1; + int m_height = -1; QImage m_oldBacking{nullptr}; std::shared_ptr m_context = nullptr; }; diff --git a/src/platform/qt/ForwarderView.cpp b/src/platform/qt/ForwarderView.cpp index 0546e7180..922ef7c16 100644 --- a/src/platform/qt/ForwarderView.cpp +++ b/src/platform/qt/ForwarderView.cpp @@ -15,7 +15,7 @@ using namespace QGBA; ForwarderView::ForwarderView(QWidget* parent) - : QDialog(parent) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) { m_ui.setupUi(this); @@ -189,7 +189,7 @@ void ForwarderView::connectBrowseButton(QAbstractButton* button, QLineEdit* line } void ForwarderView::selectImage() { - QString filename = GBAApp::app()->getOpenFileName(this, tr("Select an image"), {}); + QString filename = GBAApp::app()->getOpenFileName(this, tr("Select an image"), tr("Image files (*.png *.jpg *.bmp)")); if (filename.isEmpty()) { return; } diff --git a/src/platform/qt/FrameView.cpp b/src/platform/qt/FrameView.cpp index 1f9d4705d..2fe37e64c 100644 --- a/src/platform/qt/FrameView.cpp +++ b/src/platform/qt/FrameView.cpp @@ -31,7 +31,7 @@ using namespace QGBA; FrameView::FrameView(std::shared_ptr controller, QWidget* parent) - : AssetView(controller, parent) + : AssetView(std::move(controller), parent) { m_ui.setupUi(this); @@ -159,7 +159,7 @@ void FrameView::updateTilesGBA(bool) { uint16_t* io = static_cast(m_controller->thread()->core->board)->memory.io; QRgb backdrop = M_RGB5_TO_RGB8(static_cast(m_controller->thread()->core->board)->video.palette[0]); - GBARegisterDISPCNT gbaDispcnt = io[REG_DISPCNT >> 1]; + GBARegisterDISPCNT gbaDispcnt = io[GBA_REG(DISPCNT)]; int mode = GBARegisterDISPCNTGetMode(gbaDispcnt); std::array enabled{ @@ -233,14 +233,14 @@ void FrameView::updateTilesGBA(bool) { if (!enabled[bg]) { continue; } - if (GBARegisterBGCNTGetPriority(io[(REG_BG0CNT >> 1) + bg]) != priority) { + if (GBARegisterBGCNTGetPriority(io[GBA_REG(BG0CNT) + bg]) != priority) { continue; } QPointF offset; if (mode == 0) { - offset.setX(-(io[(REG_BG0HOFS >> 1) + (bg << 1)] & 0x1FF)); - offset.setY(-(io[(REG_BG0VOFS >> 1) + (bg << 1)] & 0x1FF)); + offset.setX(-(io[GBA_REG(BG0HOFS) + (bg << 1)] & 0x1FF)); + offset.setY(-(io[GBA_REG(BG0VOFS) + (bg << 1)] & 0x1FF)); }; m_queue.append({ { LayerId::BACKGROUND, bg }, @@ -548,6 +548,11 @@ void FrameView::newVl() { m_vl->deinit(m_vl); } m_vl = mCoreFindVF(m_currentFrame); + if (!m_vl) { + m_currentFrame->close(m_currentFrame); + m_currentFrame = nullptr; + return; + } m_vl->init(m_vl); m_vl->loadROM(m_vl, m_currentFrame); m_currentFrame = nullptr; @@ -559,7 +564,7 @@ void FrameView::newVl() { } #endif unsigned width, height; - m_vl->desiredVideoDimensions(m_vl, &width, &height); + m_vl->baseVideoSize(m_vl, &width, &height); m_framebuffer = QImage(width, height, QImage::Format_RGBX8888); m_vl->setVideoBuffer(m_vl, reinterpret_cast(m_framebuffer.bits()), width); m_vl->reset(m_vl); diff --git a/src/platform/qt/GBAApp.cpp b/src/platform/qt/GBAApp.cpp index 30287262a..fdc710c0c 100644 --- a/src/platform/qt/GBAApp.cpp +++ b/src/platform/qt/GBAApp.cpp @@ -32,6 +32,10 @@ #include "DiscordCoordinator.h" #endif +#ifdef BUILD_SDL +#include "input/SDLInputDriver.h" +#endif + using namespace QGBA; static GBAApp* g_app = nullptr; @@ -165,10 +169,14 @@ void GBAApp::continueAll(const QList& paused) { } } -QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) { +QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter, const QString& path) { QList paused; + QString base(path); + if (base.isNull()) { + base = m_configController->getOption("lastDirectory"); + } pauseAll(&paused); - QString filename = QFileDialog::getOpenFileName(owner, title, m_configController->getOption("lastDirectory"), filter); + QString filename = QFileDialog::getOpenFileName(owner, title, base, filter); continueAll(paused); if (!filename.isEmpty()) { m_configController->setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath()); @@ -176,10 +184,14 @@ QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QStr return filename; } -QStringList GBAApp::getOpenFileNames(QWidget* owner, const QString& title, const QString& filter) { +QStringList GBAApp::getOpenFileNames(QWidget* owner, const QString& title, const QString& filter, const QString& path) { QList paused; + QString base(path); + if (base.isNull()) { + base = m_configController->getOption("lastDirectory"); + } pauseAll(&paused); - QStringList filenames = QFileDialog::getOpenFileNames(owner, title, m_configController->getOption("lastDirectory"), filter); + QStringList filenames = QFileDialog::getOpenFileNames(owner, title, base, filter); continueAll(paused); if (!filenames.isEmpty()) { m_configController->setOption("lastDirectory", QFileInfo(filenames.at(0)).dir().canonicalPath()); @@ -187,10 +199,14 @@ QStringList GBAApp::getOpenFileNames(QWidget* owner, const QString& title, const return filenames; } -QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) { +QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter, const QString& path) { QList paused; + QString base(path); + if (base.isNull()) { + base = m_configController->getOption("lastDirectory"); + } pauseAll(&paused); - QString filename = QFileDialog::getSaveFileName(owner, title, m_configController->getOption("lastDirectory"), filter); + QString filename = QFileDialog::getSaveFileName(owner, title, base, filter); continueAll(paused); if (!filename.isEmpty()) { m_configController->setOption("lastDirectory", QFileInfo(filename).dir().canonicalPath()); @@ -258,17 +274,17 @@ QNetworkReply* GBAApp::httpGet(const QUrl& url) { return m_netman.get(req); } -qint64 GBAApp::submitWorkerJob(std::function job, std::function callback) { - return submitWorkerJob(job, nullptr, callback); +qint64 GBAApp::submitWorkerJob(std::function&& job, std::function&& callback) { + return submitWorkerJob(std::move(job), nullptr, std::move(callback)); } -qint64 GBAApp::submitWorkerJob(std::function job, QObject* context, std::function callback) { +qint64 GBAApp::submitWorkerJob(std::function&& job, QObject* context, std::function&& callback) { qint64 jobId = m_nextJob; ++m_nextJob; - WorkerJob* jobRunnable = new WorkerJob(jobId, job, this); + WorkerJob* jobRunnable = new WorkerJob(jobId, std::move(job), this); m_workerJobs.insert(jobId, jobRunnable); if (callback) { - waitOnJob(jobId, context, callback); + waitOnJob(jobId, context, std::move(callback)); } m_workerThreads.start(jobRunnable); return jobId; @@ -292,14 +308,15 @@ bool GBAApp::removeWorkerJob(qint64 jobId) { return success; } -bool GBAApp::waitOnJob(qint64 jobId, QObject* context, std::function callback) { +bool GBAApp::waitOnJob(qint64 jobId, QObject* context, std::function&& callback) { if (!m_workerJobs.contains(jobId)) { return false; } if (!context) { context = this; } - QMetaObject::Connection connection = connect(this, &GBAApp::jobFinished, context, [jobId, callback](qint64 testedJobId) { + QMetaObject::Connection connection = connect(this, &GBAApp::jobFinished, context, + [jobId, callback = std::move(callback)](qint64 testedJobId) { if (jobId != testedJobId) { return; } @@ -309,6 +326,25 @@ bool GBAApp::waitOnJob(qint64 jobId, QObject* context, std::function ca return true; } +void GBAApp::suspendScreensaver() { +#ifdef BUILD_SDL + SDL::suspendScreensaver(); +#endif +} + +void GBAApp::resumeScreensaver() { +#ifdef BUILD_SDL + SDL::resumeScreensaver(); +#endif +} + +void GBAApp::setScreensaverSuspendable(bool suspendable) { + UNUSED(suspendable); +#ifdef BUILD_SDL + SDL::setScreensaverSuspendable(suspendable); +#endif +} + void GBAApp::cleanupAfterUpdate() { // Remove leftover updater if there's one present QDir configDir(ConfigController::configDir()); @@ -346,7 +382,7 @@ void GBAApp::restartForUpdate() { #ifndef Q_OS_WIN QFile(extractedPath).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner); #endif - m_invokeOnExit = extractedPath; + m_invokeOnExit = std::move(extractedPath); } for (auto& window : m_windows) { @@ -361,9 +397,9 @@ void GBAApp::finishJob(qint64 jobId) { m_workerJobCallbacks.remove(jobId); } -GBAApp::WorkerJob::WorkerJob(qint64 id, std::function job, GBAApp* owner) +GBAApp::WorkerJob::WorkerJob(qint64 id, std::function&& job, GBAApp* owner) : m_id(id) - , m_job(job) + , m_job(std::move(job)) , m_owner(owner) { setAutoDelete(true); diff --git a/src/platform/qt/GBAApp.h b/src/platform/qt/GBAApp.h index 6245dba3f..2388bc297 100644 --- a/src/platform/qt/GBAApp.h +++ b/src/platform/qt/GBAApp.h @@ -63,9 +63,9 @@ public: QList windows() { return m_windows; } - QString getOpenFileName(QWidget* owner, const QString& title, const QString& filter = {}); - QStringList getOpenFileNames(QWidget* owner, const QString& title, const QString& filter = {}); - QString getSaveFileName(QWidget* owner, const QString& title, const QString& filter = {}); + QString getOpenFileName(QWidget* owner, const QString& title, const QString& filter = {}, const QString& path = {}); + QStringList getOpenFileNames(QWidget* owner, const QString& title, const QString& filter = {}, const QString& path = {}); + QString getSaveFileName(QWidget* owner, const QString& title, const QString& filter = {}, const QString& path = {}); QString getOpenDirectoryName(QWidget* owner, const QString& title, const QString& path = {}); const NoIntroDB* gameDB() const { return m_db; } @@ -74,10 +74,10 @@ public: QNetworkAccessManager* netman(); QNetworkReply* httpGet(const QUrl&); - qint64 submitWorkerJob(std::function job, std::function callback = {}); - qint64 submitWorkerJob(std::function job, QObject* context, std::function callback); + qint64 submitWorkerJob(std::function&& job, std::function&& callback = {}); + qint64 submitWorkerJob(std::function&& job, QObject* context, std::function&& callback); bool removeWorkerJob(qint64 jobId); - bool waitOnJob(qint64 jobId, QObject* context, std::function callback); + bool waitOnJob(qint64 jobId, QObject* context, std::function&& callback); ApplicationUpdater* updater() { return &m_updater; } QString invokeOnExit() { return m_invokeOnExit; } @@ -86,6 +86,10 @@ public slots: void restartForUpdate(); Window* newWindow(); + void suspendScreensaver(); + void resumeScreensaver(); + void setScreensaverSuspendable(bool); + signals: void jobFinished(qint64 jobId); @@ -99,7 +103,7 @@ private slots: private: class WorkerJob : public QRunnable { public: - WorkerJob(qint64 id, std::function job, GBAApp* owner); + WorkerJob(qint64 id, std::function&& job, GBAApp* owner); public: void run() override; diff --git a/src/platform/qt/GBAKeyEditor.cpp b/src/platform/qt/GBAKeyEditor.cpp index 7890812e7..88963afa2 100644 --- a/src/platform/qt/GBAKeyEditor.cpp +++ b/src/platform/qt/GBAKeyEditor.cpp @@ -13,6 +13,7 @@ #include #include +#include "input/InputMapper.h" #include "InputController.h" #include "KeyEditor.h" @@ -214,8 +215,9 @@ void GBAKeyEditor::setNext() { void GBAKeyEditor::save() { #ifdef BUILD_SDL - m_controller->unbindAllAxes(m_type); - m_controller->unbindAllHats(m_type); + InputMapper mapper = m_controller->mapper(m_type); + mapper.unbindAllAxes(); + mapper.unbindAllHats(); #endif bindKey(m_keyDU, GBA_KEY_UP); @@ -260,7 +262,7 @@ void GBAKeyEditor::refresh() { #endif } -void GBAKeyEditor::lookupBinding(const mInputMap* map, KeyEditor* keyEditor, GBAKey key) { +void GBAKeyEditor::lookupBinding(const mInputMap* map, KeyEditor* keyEditor, int key) { #ifdef BUILD_SDL if (m_type == SDL_BINDING_BUTTON) { int value = mInputQueryBinding(map, m_type, key); @@ -275,14 +277,14 @@ void GBAKeyEditor::lookupBinding(const mInputMap* map, KeyEditor* keyEditor, GBA void GBAKeyEditor::lookupAxes(const mInputMap* map) { mInputEnumerateAxes(map, m_type, [](int axis, const mInputAxis* description, void* user) { GBAKeyEditor* self = static_cast(user); - if (description->highDirection != GBA_KEY_NONE) { - KeyEditor* key = self->keyById(static_cast(description->highDirection)); + if (description->highDirection != -1) { + KeyEditor* key = self->keyById(description->highDirection); if (key) { key->setValueAxis(axis, GamepadAxisEvent::POSITIVE); } } - if (description->lowDirection != GBA_KEY_NONE) { - KeyEditor* key = self->keyById(static_cast(description->lowDirection)); + if (description->lowDirection != -1) { + KeyEditor* key = self->keyById(description->lowDirection); if (key) { key->setValueAxis(axis, GamepadAxisEvent::NEGATIVE); } @@ -295,25 +297,25 @@ void GBAKeyEditor::lookupHats(const mInputMap* map) { int i = 0; while (mInputQueryHat(map, m_type, i, &bindings)) { if (bindings.up >= 0) { - KeyEditor* key = keyById(static_cast(bindings.up)); + KeyEditor* key = keyById(bindings.up); if (key) { key->setValueHat(i, GamepadHatEvent::UP); } } if (bindings.right >= 0) { - KeyEditor* key = keyById(static_cast(bindings.right)); + KeyEditor* key = keyById(bindings.right); if (key) { key->setValueHat(i, GamepadHatEvent::RIGHT); } } if (bindings.down >= 0) { - KeyEditor* key = keyById(static_cast(bindings.down)); + KeyEditor* key = keyById(bindings.down); if (key) { key->setValueHat(i, GamepadHatEvent::DOWN); } } if (bindings.left >= 0) { - KeyEditor* key = keyById(static_cast(bindings.left)); + KeyEditor* key = keyById(bindings.left); if (key) { key->setValueHat(i, GamepadHatEvent::LEFT); } @@ -323,16 +325,17 @@ void GBAKeyEditor::lookupHats(const mInputMap* map) { } #endif -void GBAKeyEditor::bindKey(const KeyEditor* keyEditor, GBAKey key) { +void GBAKeyEditor::bindKey(const KeyEditor* keyEditor, int key) { + InputMapper mapper = m_controller->mapper(m_type); #ifdef BUILD_SDL if (m_type == SDL_BINDING_BUTTON && keyEditor->axis() >= 0) { - m_controller->bindAxis(m_type, keyEditor->axis(), keyEditor->direction(), key); + mapper.bindAxis(keyEditor->axis(), keyEditor->direction(), key); } if (m_type == SDL_BINDING_BUTTON && keyEditor->hat() >= 0) { - m_controller->bindHat(m_type, keyEditor->hat(), keyEditor->hatDirection(), key); + mapper.bindHat(keyEditor->hat(), keyEditor->hatDirection(), key); } #endif - m_controller->bindKey(m_type, keyEditor->value(), key); + mapper.bindKey(keyEditor->value(), key); } bool GBAKeyEditor::findFocus(KeyEditor* needle) { @@ -358,7 +361,7 @@ void GBAKeyEditor::selectGamepad(int index) { } #endif -KeyEditor* GBAKeyEditor::keyById(GBAKey key) { +KeyEditor* GBAKeyEditor::keyById(int key) { switch (key) { case GBA_KEY_UP: return m_keyDU; @@ -395,14 +398,13 @@ void GBAKeyEditor::setLocation(QWidget* widget, qreal x, qreal y) { #ifdef BUILD_SDL void GBAKeyEditor::updateJoysticks() { - m_controller->updateJoysticks(); - m_controller->recalibrateAxes(); + m_controller->update(); // Block the currentIndexChanged signal while rearranging the combo box auto wasBlocked = m_profileSelect->blockSignals(true); m_profileSelect->clear(); m_profileSelect->addItems(m_controller->connectedGamepads(m_type)); - int activeGamepad = m_controller->gamepad(m_type); + int activeGamepad = m_controller->gamepadIndex(m_type); m_profileSelect->setCurrentIndex(activeGamepad); m_profileSelect->blockSignals(wasBlocked); diff --git a/src/platform/qt/GBAKeyEditor.h b/src/platform/qt/GBAKeyEditor.h index 24b1e5c4a..9578abda9 100644 --- a/src/platform/qt/GBAKeyEditor.h +++ b/src/platform/qt/GBAKeyEditor.h @@ -54,8 +54,8 @@ private: void setLocation(QWidget* widget, qreal x, qreal y); - void lookupBinding(const mInputMap*, KeyEditor*, GBAKey); - void bindKey(const KeyEditor*, GBAKey); + void lookupBinding(const mInputMap*, KeyEditor*, int key); + void bindKey(const KeyEditor*, int key); bool findFocus(KeyEditor* needle = nullptr); @@ -64,7 +64,7 @@ private: void lookupHats(const mInputMap*); #endif - KeyEditor* keyById(GBAKey); + KeyEditor* keyById(int); QComboBox* m_profileSelect = nullptr; QWidget* m_clear = nullptr; diff --git a/src/platform/qt/GBAOverride.cpp b/src/platform/qt/GBAOverride.cpp index 885a5d3ac..57fb2048e 100644 --- a/src/platform/qt/GBAOverride.cpp +++ b/src/platform/qt/GBAOverride.cpp @@ -10,17 +10,6 @@ using namespace QGBA; -void GBAOverride::apply(struct mCore* core) { - if (core->platform(core) != mPLATFORM_GBA) { - return; - } - GBA* gba = static_cast(core->board); - if (!vbaBugCompatSet) { - override.vbaBugCompat = gba->vbaBugCompat; - } - GBAOverrideApply(gba, &override); -} - void GBAOverride::identify(const struct mCore* core) { if (core->platform(core) != mPLATFORM_GBA) { return; @@ -33,3 +22,7 @@ void GBAOverride::identify(const struct mCore* core) { void GBAOverride::save(struct Configuration* config) const { GBAOverrideSave(config, &override); } + +const void* GBAOverride::raw() const { + return &override; +} diff --git a/src/platform/qt/GBAOverride.h b/src/platform/qt/GBAOverride.h index 8b07659fd..477af0014 100644 --- a/src/platform/qt/GBAOverride.h +++ b/src/platform/qt/GBAOverride.h @@ -13,9 +13,9 @@ namespace QGBA { class GBAOverride : public Override { public: - void apply(struct mCore*) override; void identify(const struct mCore*) override; void save(struct Configuration*) const override; + const void* raw() const override; struct GBACartridgeOverride override; bool vbaBugCompatSet; diff --git a/src/platform/qt/GBOverride.cpp b/src/platform/qt/GBOverride.cpp index ed66f327d..224830437 100644 --- a/src/platform/qt/GBOverride.cpp +++ b/src/platform/qt/GBOverride.cpp @@ -11,13 +11,6 @@ using namespace QGBA; -void GBOverride::apply(struct mCore* core) { - if (core->platform(core) != mPLATFORM_GB) { - return; - } - GBOverrideApply(static_cast(core->board), &override); -} - void GBOverride::identify(const struct mCore* core) { if (core->platform(core) != mPLATFORM_GB) { return; @@ -32,3 +25,7 @@ void GBOverride::identify(const struct mCore* core) { void GBOverride::save(struct Configuration* config) const { GBOverrideSave(config, &override); } + +const void* GBOverride::raw() const { + return &override; +} diff --git a/src/platform/qt/GBOverride.h b/src/platform/qt/GBOverride.h index 82c53ca7f..e967211de 100644 --- a/src/platform/qt/GBOverride.h +++ b/src/platform/qt/GBOverride.h @@ -13,9 +13,9 @@ namespace QGBA { class GBOverride : public Override { public: - void apply(struct mCore*) override; void identify(const struct mCore*) override; void save(struct Configuration*) const override; + const void* raw() const override; struct GBCartridgeOverride override; }; diff --git a/src/platform/qt/GDBController.cpp b/src/platform/qt/GDBController.cpp index 5fd2a1768..583ffed62 100644 --- a/src/platform/qt/GDBController.cpp +++ b/src/platform/qt/GDBController.cpp @@ -20,10 +20,6 @@ ushort GDBController::port() { return m_port; } -bool GDBController::isAttached() { - return m_gameController && m_gameController->debugger() == &m_gdbStub.d; -} - void GDBController::setPort(ushort port) { m_port = port; } diff --git a/src/platform/qt/GDBController.h b/src/platform/qt/GDBController.h index d83f00028..6bf0a7132 100644 --- a/src/platform/qt/GDBController.h +++ b/src/platform/qt/GDBController.h @@ -23,7 +23,6 @@ public: public: ushort port(); - bool isAttached(); public slots: void setPort(ushort port); diff --git a/src/platform/qt/GDBWindow.cpp b/src/platform/qt/GDBWindow.cpp index 3f1f86efb..8c4738387 100644 --- a/src/platform/qt/GDBWindow.cpp +++ b/src/platform/qt/GDBWindow.cpp @@ -44,7 +44,7 @@ GDBWindow::GDBWindow(GDBController* controller, QWidget* parent) connect(m_portEdit, &QLineEdit::textChanged, this, &GDBWindow::portChanged); settingsGrid->addWidget(m_portEdit, 0, 1, Qt::AlignLeft); - m_bindAddressEdit = new QLineEdit("0.0.0.0"); + m_bindAddressEdit = new QLineEdit("127.0.0.1"); m_bindAddressEdit->setMaxLength(15); connect(m_bindAddressEdit, &QLineEdit::textChanged, this, &GDBWindow::bindAddressChanged); settingsGrid->addWidget(m_bindAddressEdit, 1, 1, Qt::AlignLeft); diff --git a/src/platform/qt/IOViewer.cpp b/src/platform/qt/IOViewer.cpp index 46c0d8dbb..531ba6955 100644 --- a/src/platform/qt/IOViewer.cpp +++ b/src/platform/qt/IOViewer.cpp @@ -1025,7 +1025,7 @@ const QList& IOViewer::registerDescriptions(mPlat regGBA.append({ { tr("Enable IRQs"), 0 }, }); - s_registers[mPLATFORM_GBA] = regGBA; + s_registers[mPLATFORM_GBA] = std::move(regGBA); #endif #ifdef M_CORE_GB QList regGB; @@ -1555,7 +1555,7 @@ const QList& IOViewer::registerDescriptions(mPlat { tr("Serial"), 3 }, { tr("Joypad"), 4 }, }); - s_registers[mPLATFORM_GB] = regGB; + s_registers[mPLATFORM_GB] = std::move(regGB); #endif return s_registers[platform]; } @@ -1579,8 +1579,8 @@ IOViewer::IOViewer(std::shared_ptr controller, QWidget* parent) #ifdef M_CORE_GBA case mPLATFORM_GBA: regs = GBAIORegisterNames; - maxRegs = REG_MAX >> 1; - m_base = BASE_IO; + maxRegs = GBA_REG_MAX >> 1; + m_base = GBA_BASE_IO; m_width = 1; break; #endif @@ -1651,8 +1651,6 @@ IOViewer::IOViewer(std::shared_ptr controller, QWidget* parent) } selectRegister(0); - - connect(controller.get(), &CoreController::stopping, this, &QWidget::close); } void IOViewer::updateRegister() { diff --git a/src/platform/qt/IOViewer.h b/src/platform/qt/IOViewer.h index 120f201e0..fabe478ac 100644 --- a/src/platform/qt/IOViewer.h +++ b/src/platform/qt/IOViewer.h @@ -28,7 +28,7 @@ public: , size(size) , readonly(readonly) , description(description) {} - RegisterItem(const QString& description, uint start, int size, QStringList items, bool readonly = false) + RegisterItem(const QString& description, uint start, int size, const QStringList& items, bool readonly = false) : start(start) , size(size) , readonly(readonly) diff --git a/src/platform/qt/InputController.cpp b/src/platform/qt/InputController.cpp index a0fb91397..337e7df6b 100644 --- a/src/platform/qt/InputController.cpp +++ b/src/platform/qt/InputController.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 @@ -6,8 +6,8 @@ #include "InputController.h" #include "ConfigController.h" -#include "GamepadAxisEvent.h" -#include "GamepadButtonEvent.h" +#include "input/Gamepad.h" +#include "input/GamepadButtonEvent.h" #include "InputProfile.h" #include "LogController.h" #include "utils.h" @@ -25,37 +25,28 @@ using namespace QGBA; -#ifdef BUILD_SDL -int InputController::s_sdlInited = 0; -mSDLEvents InputController::s_sdlEvents; -#endif +int InputController::s_claimedPlayers = 0; -InputController::InputController(int playerId, QWidget* topLevel, QObject* parent) +InputController::InputController(QWidget* topLevel, QObject* parent) : QObject(parent) - , m_playerId(playerId) + , m_playerId(claimPlayer()) , m_topLevel(topLevel) , m_focusParent(topLevel) { mInputMapInit(&m_inputMap, &GBAInputInfo); -#ifdef BUILD_SDL - if (s_sdlInited == 0) { - mSDLInitEvents(&s_sdlEvents); - } - ++s_sdlInited; - m_sdlPlayer.bindings = &m_inputMap; - updateJoysticks(); -#endif - -#ifdef BUILD_SDL connect(&m_gamepadTimer, &QTimer::timeout, [this]() { - testGamepad(SDL_BINDING_BUTTON); + for (auto& driver : m_inputDrivers) { + if (driver->supportsPolling() && driver->supportsGamepads()) { + testGamepad(driver->type()); + } + } if (m_playerId == 0) { - updateJoysticks(); + update(); } }); -#endif - m_gamepadTimer.setInterval(50); + + m_gamepadTimer.setInterval(15); m_gamepadTimer.start(); #ifdef BUILD_QT_MULTIMEDIA @@ -141,43 +132,33 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren InputController::~InputController() { mInputMapDeinit(&m_inputMap); + freePlayer(m_playerId); +} -#ifdef BUILD_SDL - if (m_playerAttached) { - mSDLDetachPlayer(&s_sdlEvents, &m_sdlPlayer); +void InputController::addInputDriver(std::shared_ptr driver) { + m_inputDrivers[driver->type()] = driver; + if (!m_sensorDriver && driver->supportsSensors()) { + m_sensorDriver = driver->type(); } - - --s_sdlInited; - if (s_sdlInited == 0) { - mSDLDeinitEvents(&s_sdlEvents); - } -#endif } void InputController::setConfiguration(ConfigController* config) { m_config = config; loadConfiguration(KEYBOARD); -#ifdef BUILD_SDL - mSDLEventsLoadConfig(&s_sdlEvents, config->input()); - if (!m_playerAttached) { - m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer); + for (auto& driver : m_inputDrivers) { + driver->loadConfiguration(config); } - if (!loadConfiguration(SDL_BINDING_BUTTON)) { - mSDLInitBindingsGBA(&m_inputMap); - } - loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON)); -#endif } bool InputController::loadConfiguration(uint32_t type) { if (!mInputMapLoad(&m_inputMap, type, m_config->input())) { return false; } -#ifdef BUILD_SDL - if (m_playerAttached) { - mSDLPlayerLoadConfig(&m_sdlPlayer, m_config->input()); + auto driver = m_inputDrivers.value(type); + if (!driver) { + return false; } -#endif + driver->loadConfiguration(m_config); return true; } @@ -186,7 +167,6 @@ bool InputController::loadProfile(uint32_t type, const QString& profile) { return false; } bool loaded = mInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData()); - recalibrateAxes(); if (!loaded) { const InputProfile* ip = InputProfile::findProfile(profile); if (ip) { @@ -200,18 +180,18 @@ bool InputController::loadProfile(uint32_t type, const QString& profile) { void InputController::saveConfiguration() { saveConfiguration(KEYBOARD); -#ifdef BUILD_SDL - saveConfiguration(SDL_BINDING_BUTTON); - saveProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON)); - if (m_playerAttached) { - mSDLPlayerSaveConfig(&m_sdlPlayer, m_config->input()); + for (auto& driver : m_inputDrivers) { + driver->saveConfiguration(m_config); } -#endif m_config->write(); } void InputController::saveConfiguration(uint32_t type) { mInputMapSave(&m_inputMap, type, m_config->input()); + auto driver = m_inputDrivers.value(type); + if (driver) { + driver->saveConfiguration(m_config); + } m_config->write(); } @@ -223,373 +203,240 @@ void InputController::saveProfile(uint32_t type, const QString& profile) { m_config->write(); } -const char* InputController::profileForType(uint32_t type) { - UNUSED(type); -#ifdef BUILD_SDL - if (type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) { -#if SDL_VERSION_ATLEAST(2, 0, 0) - return SDL_JoystickName(m_sdlPlayer.joystick->joystick); -#else - return SDL_JoystickName(SDL_JoystickIndex(m_sdlPlayer.joystick->joystick)); -#endif +QString InputController::profileForType(uint32_t type) { + auto driver = m_inputDrivers.value(type); + if (!driver) { + return {}; } -#endif - return 0; + return driver->currentProfile(); +} + +void InputController::setGamepadDriver(uint32_t type) { + auto driver = m_inputDrivers.value(type); + if (!driver || !driver->supportsGamepads()) { + return; + } + m_gamepadDriver = type; } QStringList InputController::connectedGamepads(uint32_t type) const { - UNUSED(type); - -#ifdef BUILD_SDL - if (type == SDL_BINDING_BUTTON) { - QStringList pads; - for (size_t i = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) { - const char* name; -#if SDL_VERSION_ATLEAST(2, 0, 0) - name = SDL_JoystickName(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick); -#else - name = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick)); -#endif - if (name) { - pads.append(QString(name)); - } else { - pads.append(QString()); - } - } - return pads; + if (!type) { + type = m_gamepadDriver; + } + const auto& driver = m_inputDrivers.value(type); + if (!driver) { + return {}; } -#endif - return QStringList(); + QStringList pads; + for (auto& pad : driver->connectedGamepads()) { + pads.append(pad->visibleName()); + } + return pads; } -int InputController::gamepad(uint32_t type) const { -#ifdef BUILD_SDL - if (type == SDL_BINDING_BUTTON) { - return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0; +int InputController::gamepadIndex(uint32_t type) const { + if (!type) { + type = m_gamepadDriver; } -#endif - return 0; + const auto& driver = m_inputDrivers.value(type); + if (!driver) { + return -1; + } + return driver->activeGamepadIndex(); } void InputController::setGamepad(uint32_t type, int index) { -#ifdef BUILD_SDL - if (type == SDL_BINDING_BUTTON) { - mSDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); + if (!type) { + type = m_gamepadDriver; } -#endif + auto driver = m_inputDrivers.value(type); + if (!driver) { + return; + } + driver->setActiveGamepad(index); +} + +void InputController::setGamepad(int index) { + setGamepad(0, index); } void InputController::setPreferredGamepad(uint32_t type, int index) { if (!m_config) { return; } -#ifdef BUILD_SDL -#if SDL_VERSION_ATLEAST(2, 0, 0) - char name[34] = {0}; - SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, index)->joystick), name, sizeof(name)); -#else - const char* name = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, index)->joystick)); - if (!name) { + if (!type) { + type = m_gamepadDriver; + } + auto driver = m_inputDrivers.value(type); + if (!driver) { return; } -#endif - mInputSetPreferredDevice(m_config->input(), "gba", type, m_playerId, name); -#else - UNUSED(type); - UNUSED(index); -#endif + + auto pads = driver->connectedGamepads(); + if (index >= pads.count()) { + return; + } + + QString name = pads[index]->name(); + if (name.isEmpty()) { + return; + } + mInputSetPreferredDevice(m_config->input(), "gba", type, m_playerId, name.toUtf8().constData()); } -mRumble* InputController::rumble() { -#ifdef BUILD_SDL -#if SDL_VERSION_ATLEAST(2, 0, 0) - if (m_playerAttached) { - return &m_sdlPlayer.rumble.d; +void InputController::setPreferredGamepad(int index) { + setPreferredGamepad(0, index); +} + +InputMapper InputController::mapper(uint32_t type) { + return InputMapper(&m_inputMap, type); +} + +InputMapper InputController::mapper(InputDriver* driver) { + return InputMapper(&m_inputMap, driver->type()); +} + +InputMapper InputController::mapper(InputSource* source) { + return InputMapper(&m_inputMap, source->type()); +} + +void InputController::setSensorDriver(uint32_t type) { + auto driver = m_inputDrivers.value(type); + if (!driver || !driver->supportsSensors()) { + return; + } + m_sensorDriver = type; +} + + +mRumble* InputController::rumble() { + auto driver = m_inputDrivers.value(m_sensorDriver); + if (driver) { + return driver->rumble(); } -#endif -#endif return nullptr; } mRotationSource* InputController::rotationSource() { -#ifdef BUILD_SDL - if (m_playerAttached) { - return &m_sdlPlayer.rotation.d; + auto driver = m_inputDrivers.value(m_sensorDriver); + if (driver) { + return driver->rotationSource(); } -#endif return nullptr; } -void InputController::registerTiltAxisX(int axis) { -#ifdef BUILD_SDL - if (m_playerAttached) { - m_sdlPlayer.rotation.axisX = axis; - } -#endif +int InputController::mapKeyboard(int key) const { + return mInputMapKey(&m_inputMap, KEYBOARD, key); } -void InputController::registerTiltAxisY(int axis) { -#ifdef BUILD_SDL - if (m_playerAttached) { - m_sdlPlayer.rotation.axisY = axis; - } -#endif -} - -void InputController::registerGyroAxisX(int axis) { -#ifdef BUILD_SDL - if (m_playerAttached) { - m_sdlPlayer.rotation.gyroX = axis; - if (m_sdlPlayer.rotation.gyroY == axis) { - m_sdlPlayer.rotation.gyroZ = axis; - } else { - m_sdlPlayer.rotation.gyroZ = -1; +void InputController::update() { + for (auto& driver : m_inputDrivers) { + QString profile = profileForType(driver->type()); + driver->update(); + QString newProfile = profileForType(driver->type()); + if (profile != newProfile) { + loadProfile(driver->type(), newProfile); } } -#endif -} - -void InputController::registerGyroAxisY(int axis) { -#ifdef BUILD_SDL - if (m_playerAttached) { - m_sdlPlayer.rotation.gyroY = axis; - if (m_sdlPlayer.rotation.gyroX == axis) { - m_sdlPlayer.rotation.gyroZ = axis; - } else { - m_sdlPlayer.rotation.gyroZ = -1; - } - } -#endif -} - -float InputController::gyroSensitivity() const { -#ifdef BUILD_SDL - if (m_playerAttached) { - return m_sdlPlayer.rotation.gyroSensitivity; - } -#endif - return 0; -} - -void InputController::setGyroSensitivity(float sensitivity) { -#ifdef BUILD_SDL - if (m_playerAttached) { - m_sdlPlayer.rotation.gyroSensitivity = sensitivity; - } -#endif -} - -GBAKey InputController::mapKeyboard(int key) const { - return static_cast(mInputMapKey(&m_inputMap, KEYBOARD, key)); -} - -void InputController::bindKey(uint32_t type, int key, GBAKey gbaKey) { - return mInputBindKey(&m_inputMap, type, key, gbaKey); -} - -void InputController::updateJoysticks() { -#ifdef BUILD_SDL - QString profile = profileForType(SDL_BINDING_BUTTON); - mSDLUpdateJoysticks(&s_sdlEvents, m_config->input()); - QString newProfile = profileForType(SDL_BINDING_BUTTON); - if (profile != newProfile) { - loadProfile(SDL_BINDING_BUTTON, newProfile); - } -#endif + emit updated(); } int InputController::pollEvents() { int activeButtons = 0; -#ifdef BUILD_SDL - if (m_playerAttached && m_sdlPlayer.joystick) { - SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick; - SDL_JoystickUpdate(); - int numButtons = SDL_JoystickNumButtons(joystick); - int i; - QReadLocker l(&m_eventsLock); - for (i = 0; i < numButtons; ++i) { - GBAKey key = static_cast(mInputMapKey(&m_inputMap, SDL_BINDING_BUTTON, i)); - if (key == GBA_KEY_NONE) { - continue; - } - if (hasPendingEvent(key)) { - continue; - } - if (SDL_JoystickGetButton(joystick, i)) { - activeButtons |= 1 << key; - } - } - l.unlock(); - int numHats = SDL_JoystickNumHats(joystick); - for (i = 0; i < numHats; ++i) { - int hat = SDL_JoystickGetHat(joystick, i); - activeButtons |= mInputMapHat(&m_inputMap, SDL_BINDING_BUTTON, i, hat); - } - - int numAxes = SDL_JoystickNumAxes(joystick); - for (i = 0; i < numAxes; ++i) { - int value = SDL_JoystickGetAxis(joystick, i); - - enum GBAKey key = static_cast(mInputMapAxis(&m_inputMap, SDL_BINDING_BUTTON, i, value)); - if (key != GBA_KEY_NONE) { - activeButtons |= 1 << key; - } + for (auto& pad : gamepads()) { + InputMapper im(mapper(pad.get())); + activeButtons |= im.mapKeys(pad->currentButtons()); + activeButtons |= im.mapAxes(pad->currentAxes()); + activeButtons |= im.mapHats(pad->currentHats()); + } + QReadLocker l(&m_eventsLock); + for (int i = 0; i < GBA_KEY_MAX; ++i) { + if ((activeButtons & (1 << i)) && hasPendingEvent(i)) { + activeButtons ^= 1 << i; } } -#endif return activeButtons; } -QSet InputController::activeGamepadButtons(int type) { +std::shared_ptr InputController::gamepad(uint32_t type) { + auto driver = m_inputDrivers.value(type); + if (!driver) { + return nullptr; + } + if (!driver->supportsGamepads()) { + return nullptr; + } + + return driver->activeGamepad(); +} + +QList> InputController::gamepads() { + QList> pads; + for (auto& driver : m_inputDrivers) { + if (!driver->supportsGamepads()) { + continue; + } + std::shared_ptr pad = driver->activeGamepad(); + if (pad) { + pads.append(pad); + } + } + return pads; +} + +QSet InputController::activeGamepadButtons(uint32_t type) { QSet activeButtons; -#ifdef BUILD_SDL - if (m_playerAttached && type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) { - SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick; - SDL_JoystickUpdate(); - int numButtons = SDL_JoystickNumButtons(joystick); - int i; - for (i = 0; i < numButtons; ++i) { - if (SDL_JoystickGetButton(joystick, i)) { - activeButtons.insert(i); - } + std::shared_ptr pad = gamepad(type); + if (!pad) { + return {}; + } + auto allButtons = pad->currentButtons(); + for (int i = 0; i < allButtons.size(); ++i) { + if (allButtons[i]) { + activeButtons.insert(i); } } -#endif return activeButtons; } -void InputController::recalibrateAxes() { -#ifdef BUILD_SDL - if (m_playerAttached && m_sdlPlayer.joystick) { - SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick; - SDL_JoystickUpdate(); - int numAxes = SDL_JoystickNumAxes(joystick); - if (numAxes < 1) { - return; - } - m_deadzones.resize(numAxes); - int i; - for (i = 0; i < numAxes; ++i) { - m_deadzones[i] = SDL_JoystickGetAxis(joystick, i); - } - } -#endif -} - -QSet> InputController::activeGamepadAxes(int type) { +QSet> InputController::activeGamepadAxes(uint32_t type) { QSet> activeAxes; -#ifdef BUILD_SDL - if (m_playerAttached && type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) { - SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick; - SDL_JoystickUpdate(); - int numAxes = SDL_JoystickNumAxes(joystick); - if (numAxes < 1) { - return activeAxes; + std::shared_ptr pad = gamepad(type); + if (!pad) { + return {}; + } + InputMapper im(mapper(type)); + auto allAxes = pad->currentAxes(); + for (int i = 0; i < allAxes.size(); ++i) { + if (allAxes[i] - im.axisCenter(i) >= im.axisThreshold(i)) { + activeAxes.insert(qMakePair(i, GamepadAxisEvent::POSITIVE)); + continue; } - m_deadzones.resize(numAxes); - int i; - for (i = 0; i < numAxes; ++i) { - int32_t axis = SDL_JoystickGetAxis(joystick, i); - axis -= m_deadzones[i]; - if (axis >= AXIS_THRESHOLD || axis <= -AXIS_THRESHOLD) { - activeAxes.insert(qMakePair(i, axis > 0 ? GamepadAxisEvent::POSITIVE : GamepadAxisEvent::NEGATIVE)); - } + if (allAxes[i] - im.axisCenter(i) <= -im.axisThreshold(i)) { + activeAxes.insert(qMakePair(i, GamepadAxisEvent::NEGATIVE)); + continue; } } -#endif return activeAxes; } -void InputController::bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction direction, GBAKey key) { - const mInputAxis* old = mInputQueryAxis(&m_inputMap, type, axis); - mInputAxis description = { GBA_KEY_NONE, GBA_KEY_NONE, -AXIS_THRESHOLD, AXIS_THRESHOLD }; - if (old) { - description = *old; - } - int deadzone = 0; - if (axis > 0 && m_deadzones.size() > axis) { - deadzone = m_deadzones[axis]; - } - switch (direction) { - case GamepadAxisEvent::NEGATIVE: - description.lowDirection = key; - - description.deadLow = deadzone - AXIS_THRESHOLD; - break; - case GamepadAxisEvent::POSITIVE: - description.highDirection = key; - description.deadHigh = deadzone + AXIS_THRESHOLD; - break; - default: - return; - } - mInputBindAxis(&m_inputMap, type, axis, &description); -} - -void InputController::unbindAllAxes(uint32_t type) { - mInputUnbindAllAxes(&m_inputMap, type); -} - -QSet> InputController::activeGamepadHats(int type) { +QSet> InputController::activeGamepadHats(uint32_t type) { QSet> activeHats; -#ifdef BUILD_SDL - if (m_playerAttached && type == SDL_BINDING_BUTTON && m_sdlPlayer.joystick) { - SDL_Joystick* joystick = m_sdlPlayer.joystick->joystick; - SDL_JoystickUpdate(); - int numHats = SDL_JoystickNumHats(joystick); - if (numHats < 1) { - return activeHats; - } - - int i; - for (i = 0; i < numHats; ++i) { - int hat = SDL_JoystickGetHat(joystick, i); - if (hat & GamepadHatEvent::UP) { - activeHats.insert(qMakePair(i, GamepadHatEvent::UP)); - } - if (hat & GamepadHatEvent::RIGHT) { - activeHats.insert(qMakePair(i, GamepadHatEvent::RIGHT)); - } - if (hat & GamepadHatEvent::DOWN) { - activeHats.insert(qMakePair(i, GamepadHatEvent::DOWN)); - } - if (hat & GamepadHatEvent::LEFT) { - activeHats.insert(qMakePair(i, GamepadHatEvent::LEFT)); - } + std::shared_ptr pad = gamepad(type); + if (!pad) { + return {}; + } + auto allHats = pad->currentHats(); + for (int i = 0; i < allHats.size(); ++i) { + if (allHats[i] != GamepadHatEvent::CENTER) { + activeHats.insert(qMakePair(i, allHats[i])); } } -#endif return activeHats; } -void InputController::bindHat(uint32_t type, int hat, GamepadHatEvent::Direction direction, GBAKey gbaKey) { - mInputHatBindings bindings{ -1, -1, -1, -1 }; - mInputQueryHat(&m_inputMap, type, hat, &bindings); - switch (direction) { - case GamepadHatEvent::UP: - bindings.up = gbaKey; - break; - case GamepadHatEvent::RIGHT: - bindings.right = gbaKey; - break; - case GamepadHatEvent::DOWN: - bindings.down = gbaKey; - break; - case GamepadHatEvent::LEFT: - bindings.left = gbaKey; - break; - default: - return; - } - mInputBindHat(&m_inputMap, type, hat, &bindings); -} - -void InputController::unbindAllHats(uint32_t type) { - mInputUnbindAllHats(&m_inputMap, type); -} - -void InputController::testGamepad(int type) { +void InputController::testGamepad(uint32_t type) { QWriteLocker l(&m_eventsLock); auto activeAxes = activeGamepadAxes(type); auto oldAxes = m_activeAxes; @@ -614,16 +461,16 @@ void InputController::testGamepad(int type) { bool newlyAboveThreshold = activeAxes.contains(axis); if (newlyAboveThreshold) { GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, newlyAboveThreshold, type, this); - postPendingEvent(event->gbaKey()); + postPendingEvent(event->platformKey()); sendGamepadEvent(event); if (!event->isAccepted()) { - clearPendingEvent(event->gbaKey()); + clearPendingEvent(event->platformKey()); } } } - for (auto axis : oldAxes) { + for (auto& axis : oldAxes) { GamepadAxisEvent* event = new GamepadAxisEvent(axis.first, axis.second, false, type, this); - clearPendingEvent(event->gbaKey()); + clearPendingEvent(event->platformKey()); sendGamepadEvent(event); } @@ -636,15 +483,15 @@ void InputController::testGamepad(int type) { for (int button : activeButtons) { GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Down(), button, type, this); - postPendingEvent(event->gbaKey()); + postPendingEvent(event->platformKey()); sendGamepadEvent(event); if (!event->isAccepted()) { - clearPendingEvent(event->gbaKey()); + clearPendingEvent(event->platformKey()); } } for (int button : oldButtons) { GamepadButtonEvent* event = new GamepadButtonEvent(GamepadButtonEvent::Up(), button, type, this); - clearPendingEvent(event->gbaKey()); + clearPendingEvent(event->platformKey()); sendGamepadEvent(event); } @@ -653,15 +500,15 @@ void InputController::testGamepad(int type) { for (auto& hat : activeHats) { GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Down(), hat.first, hat.second, type, this); - postPendingEvent(event->gbaKey()); + postPendingEvents(event->platformKeys()); sendGamepadEvent(event); if (!event->isAccepted()) { - clearPendingEvent(event->gbaKey()); + clearPendingEvents(event->platformKeys()); } } for (auto& hat : oldHats) { GamepadHatEvent* event = new GamepadHatEvent(GamepadHatEvent::Up(), hat.first, hat.second, type, this); - clearPendingEvent(event->gbaKey()); + clearPendingEvents(event->platformKeys()); sendGamepadEvent(event); } } @@ -679,40 +526,46 @@ void InputController::sendGamepadEvent(QEvent* event) { QApplication::postEvent(focusWidget, event, Qt::HighEventPriority); } -void InputController::postPendingEvent(GBAKey key) { +void InputController::postPendingEvent(int key) { m_pendingEvents.insert(key); } -void InputController::clearPendingEvent(GBAKey key) { +void InputController::clearPendingEvent(int key) { m_pendingEvents.remove(key); } -bool InputController::hasPendingEvent(GBAKey key) const { +void InputController::postPendingEvents(int keys) { + for (int i = 0; keys; ++i, keys >>= 1) { + if (keys & 1) { + m_pendingEvents.insert(i); + } + } +} + +void InputController::clearPendingEvents(int keys) { + for (int i = 0; keys; ++i, keys >>= 1) { + if (keys & 1) { + m_pendingEvents.remove(i); + } + } +} + +bool InputController::hasPendingEvent(int key) const { return m_pendingEvents.contains(key); } -void InputController::suspendScreensaver() { -#ifdef BUILD_SDL -#if SDL_VERSION_ATLEAST(2, 0, 0) - mSDLSuspendScreensaver(&s_sdlEvents); -#endif -#endif +int InputController::claimPlayer() { + for (int i = 0; i < MAX_GBAS; ++i) { + if (!(s_claimedPlayers & (1 << i))) { + s_claimedPlayers |= 1 << i; + return i; + } + } + qFatal("Can't claim 5th player. Please report this bug."); } -void InputController::resumeScreensaver() { -#ifdef BUILD_SDL -#if SDL_VERSION_ATLEAST(2, 0, 0) - mSDLResumeScreensaver(&s_sdlEvents); -#endif -#endif -} - -void InputController::setScreensaverSuspendable(bool suspendable) { -#ifdef BUILD_SDL -#if SDL_VERSION_ATLEAST(2, 0, 0) - mSDLSetScreensaverSuspendable(&s_sdlEvents, suspendable); -#endif -#endif +void InputController::freePlayer(int player) { + s_claimedPlayers &= ~(1 << player); } void InputController::stealFocus(QWidget* focus) { diff --git a/src/platform/qt/InputController.h b/src/platform/qt/InputController.h index a370ba80e..06871ff1e 100644 --- a/src/platform/qt/InputController.h +++ b/src/platform/qt/InputController.h @@ -1,13 +1,16 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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/. */ #pragma once -#include "GamepadAxisEvent.h" -#include "GamepadHatEvent.h" +#include "input/GamepadAxisEvent.h" +#include "input/GamepadHatEvent.h" +#include "input/InputDriver.h" +#include "input/InputMapper.h" +#include #include #include #include @@ -18,16 +21,13 @@ #include +#include #include -#include - -#ifdef BUILD_SDL -#include "platform/sdl/sdl-events.h" -#endif - #ifdef BUILD_QT_MULTIMEDIA +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) #include "VideoDumper.h" +#endif #include #endif @@ -37,6 +37,8 @@ struct mRumble; namespace QGBA { class ConfigController; +class Gamepad; +class InputSource; class InputController : public QObject { Q_OBJECT @@ -51,49 +53,48 @@ public: static const uint32_t KEYBOARD = 0x51545F4B; - InputController(int playerId = 0, QWidget* topLevel = nullptr, QObject* parent = nullptr); + InputController(QWidget* topLevel = nullptr, QObject* parent = nullptr); ~InputController(); + void addInputDriver(std::shared_ptr); + + int playerId() const { return m_playerId; } + void setConfiguration(ConfigController* config); void saveConfiguration(); bool loadConfiguration(uint32_t type); bool loadProfile(uint32_t type, const QString& profile); void saveConfiguration(uint32_t type); void saveProfile(uint32_t type, const QString& profile); - const char* profileForType(uint32_t type); + QString profileForType(uint32_t type); - GBAKey mapKeyboard(int key) const; - - void bindKey(uint32_t type, int key, GBAKey); + int mapKeyboard(int key) const; + mInputMap* map() { return &m_inputMap; } const mInputMap* map() const { return &m_inputMap; } int pollEvents(); static const int32_t AXIS_THRESHOLD = 0x3000; - QSet activeGamepadButtons(int type); - QSet> activeGamepadAxes(int type); - QSet> activeGamepadHats(int type); - void recalibrateAxes(); - void bindAxis(uint32_t type, int axis, GamepadAxisEvent::Direction, GBAKey); - void unbindAllAxes(uint32_t type); + void setGamepadDriver(uint32_t type); + const InputDriver* gamepadDriver() const { return m_inputDrivers.value(m_gamepadDriver).get(); } + InputDriver* gamepadDriver() { return m_inputDrivers.value(m_gamepadDriver).get(); } - void bindHat(uint32_t type, int hat, GamepadHatEvent::Direction, GBAKey); - void unbindAllHats(uint32_t type); - - QStringList connectedGamepads(uint32_t type) const; - int gamepad(uint32_t type) const; + QStringList connectedGamepads(uint32_t type = 0) const; + int gamepadIndex(uint32_t type = 0) const; void setGamepad(uint32_t type, int index); + void setGamepad(int index); void setPreferredGamepad(uint32_t type, int index); + void setPreferredGamepad(int index); - void registerTiltAxisX(int axis); - void registerTiltAxisY(int axis); - void registerGyroAxisX(int axis); - void registerGyroAxisY(int axis); + InputMapper mapper(uint32_t type); + InputMapper mapper(InputDriver*); + InputMapper mapper(InputSource*); - float gyroSensitivity() const; - void setGyroSensitivity(float sensitivity); + void setSensorDriver(uint32_t type); + const InputDriver* sensorDriver() const { return m_inputDrivers.value(m_sensorDriver).get(); } + InputDriver* sensorDriver() { return m_inputDrivers.value(m_sensorDriver).get(); } void stealFocus(QWidget* focus); void releaseFocus(QWidget* focus); @@ -106,17 +107,13 @@ public: GBALuminanceSource* luminance() { return &m_lux; } signals: + void updated(); void profileLoaded(const QString& profile); void luminanceValueChanged(int value); public slots: - void testGamepad(int type); - void updateJoysticks(); - - // TODO: Move these to somewhere that makes sense - void suspendScreensaver(); - void resumeScreensaver(); - void setScreensaverSuspendable(bool); + void testGamepad(uint32_t type); + void update(); void increaseLuminanceLevel(); void decreaseLuminanceLevel(); @@ -136,11 +133,23 @@ private slots: void teardownCam(); private: - void postPendingEvent(GBAKey); - void clearPendingEvent(GBAKey); - bool hasPendingEvent(GBAKey) const; + void postPendingEvent(int key); + void clearPendingEvent(int key); + void postPendingEvents(int keys); + void clearPendingEvents(int keys); + bool hasPendingEvent(int key) const; void sendGamepadEvent(QEvent*); + static int claimPlayer(); + static void freePlayer(int); + + std::shared_ptr gamepad(uint32_t type); + QList> gamepads(); + + QSet activeGamepadButtons(uint32_t type); + QSet> activeGamepadAxes(uint32_t type); + QSet> activeGamepadHats(uint32_t type); + struct InputControllerLux : GBALuminanceSource { InputController* p; uint8_t value; @@ -161,30 +170,28 @@ private: bool m_cameraActive = false; QByteArray m_cameraDevice; std::unique_ptr m_camera; +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) VideoDumper m_videoDumper; +#endif #endif + static int s_claimedPlayers; mInputMap m_inputMap; ConfigController* m_config = nullptr; int m_playerId; QWidget* m_topLevel; QWidget* m_focusParent; -#ifdef BUILD_SDL - static int s_sdlInited; - static mSDLEvents s_sdlEvents; - mSDLPlayer m_sdlPlayer{}; - bool m_playerAttached = false; -#endif - - QVector m_deadzones; + QHash> m_inputDrivers; + uint32_t m_gamepadDriver = 0; + uint32_t m_sensorDriver = 0; QSet m_activeButtons; QSet> m_activeAxes; QSet> m_activeHats; QTimer m_gamepadTimer{nullptr}; - QSet m_pendingEvents; + QSet m_pendingEvents; QReadWriteLock m_eventsLock; }; diff --git a/src/platform/qt/InputProfile.cpp b/src/platform/qt/InputProfile.cpp index aedc47f6e..852dbb413 100644 --- a/src/platform/qt/InputProfile.cpp +++ b/src/platform/qt/InputProfile.cpp @@ -5,9 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "InputProfile.h" +#include "input/InputMapper.h" #include "InputController.h" -#include +#include using namespace QGBA; @@ -201,8 +202,8 @@ constexpr InputProfile::InputProfile(const char* name, const InputProfile* InputProfile::findProfile(const QString& name) { for (size_t i = 0; i < sizeof(s_defaultMaps) / sizeof(*s_defaultMaps); ++i) { - QRegExp re(s_defaultMaps[i].m_profileName); - if (re.exactMatch(name)) { + QRegularExpression re(QString("^%1$").arg(s_defaultMaps[i].m_profileName)); + if (re.match(name).hasMatch()) { return &s_defaultMaps[i]; } } @@ -210,17 +211,23 @@ const InputProfile* InputProfile::findProfile(const QString& name) { } void InputProfile::apply(InputController* controller) const { - for (size_t i = 0; i < GBA_KEY_MAX; ++i) { -#ifdef BUILD_SDL - controller->bindKey(SDL_BINDING_BUTTON, m_keys[i], static_cast(i)); - controller->bindAxis(SDL_BINDING_BUTTON, m_axes[i].axis, m_axes[i].direction, static_cast(i)); -#endif + auto gamepadDriver = controller->gamepadDriver(); + if (gamepadDriver) { + InputMapper mapper = controller->mapper(gamepadDriver); + for (size_t i = 0; i < GBA_KEY_MAX; ++i) { + mapper.bindKey(m_keys[i], i); + mapper.bindAxis(m_axes[i].axis, m_axes[i].direction, i); + } + } + + InputDriver* sensorDriver = controller->sensorDriver(); + if (sensorDriver) { + sensorDriver->registerTiltAxisX(m_tiltAxis.x); + sensorDriver->registerTiltAxisY(m_tiltAxis.y); + sensorDriver->registerGyroAxisX(m_gyroAxis.x); + sensorDriver->registerGyroAxisY(m_gyroAxis.y); + sensorDriver->setGyroSensitivity(m_gyroSensitivity); } - controller->registerTiltAxisX(m_tiltAxis.x); - controller->registerTiltAxisY(m_tiltAxis.y); - controller->registerGyroAxisX(m_gyroAxis.x); - controller->registerGyroAxisY(m_gyroAxis.y); - controller->setGyroSensitivity(m_gyroSensitivity); } bool InputProfile::lookupShortcutButton(const QString& shortcutName, int* button) const { diff --git a/src/platform/qt/InputProfile.h b/src/platform/qt/InputProfile.h index 4e43d16a7..a7670a40c 100644 --- a/src/platform/qt/InputProfile.h +++ b/src/platform/qt/InputProfile.h @@ -5,9 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once -#include "GamepadAxisEvent.h" +#include "input/GamepadAxisEvent.h" #include +#include namespace QGBA { diff --git a/src/platform/qt/KeyEditor.cpp b/src/platform/qt/KeyEditor.cpp index 95b83a9e8..7d3ba1990 100644 --- a/src/platform/qt/KeyEditor.cpp +++ b/src/platform/qt/KeyEditor.cpp @@ -5,9 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "KeyEditor.h" -#include "GamepadAxisEvent.h" -#include "GamepadButtonEvent.h" +#include "input/GamepadAxisEvent.h" +#include "input/GamepadButtonEvent.h" #include "ShortcutController.h" +#include "utils.h" #include #include @@ -33,35 +34,7 @@ void KeyEditor::setValue(int key) { if (key < 0) { setText(tr("---")); } else { - QKeySequence seq(key); - switch (key) { -#ifndef Q_OS_MAC - case Qt::Key_Shift: - setText(QCoreApplication::translate("QShortcut", "Shift")); - break; - case Qt::Key_Control: - setText(QCoreApplication::translate("QShortcut", "Control")); - break; - case Qt::Key_Alt: - setText(QCoreApplication::translate("QShortcut", "Alt")); - break; - case Qt::Key_Meta: - setText(QCoreApplication::translate("QShortcut", "Meta")); - break; -#endif - case Qt::Key_Super_L: - setText(tr("Super (L)")); - break; - case Qt::Key_Super_R: - setText(tr("Super (R)")); - break; - case Qt::Key_Menu: - setText(tr("Menu")); - break; - default: - setText(QKeySequence(key).toString(QKeySequence::NativeText)); - break; - } + setText(keyName(key)); } } emit valueChanged(key); diff --git a/src/platform/qt/KeyEditor.h b/src/platform/qt/KeyEditor.h index e74df7f27..c1bb56fae 100644 --- a/src/platform/qt/KeyEditor.h +++ b/src/platform/qt/KeyEditor.h @@ -5,8 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once -#include "GamepadAxisEvent.h" -#include "GamepadHatEvent.h" +#include "input/GamepadAxisEvent.h" +#include "input/GamepadHatEvent.h" #include #include diff --git a/src/platform/qt/LoadSaveState.cpp b/src/platform/qt/LoadSaveState.cpp index 3198a4c90..f5dad2336 100644 --- a/src/platform/qt/LoadSaveState.cpp +++ b/src/platform/qt/LoadSaveState.cpp @@ -6,8 +6,8 @@ #include "LoadSaveState.h" #include "CoreController.h" -#include "GamepadAxisEvent.h" -#include "GamepadButtonEvent.h" +#include "input/GamepadAxisEvent.h" +#include "input/GamepadButtonEvent.h" #include "VFileDevice.h" #include "utils.h" @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -42,13 +43,12 @@ LoadSaveState::LoadSaveState(std::shared_ptr controller, QWidget m_slots[7] = m_ui.state8; m_slots[8] = m_ui.state9; - unsigned width, height; - controller->thread()->core->desiredVideoDimensions(controller->thread()->core, &width, &height); + QSize size = controller->screenDimensions(); int i; for (i = 0; i < NUM_SLOTS; ++i) { loadState(i + 1); m_slots[i]->installEventFilter(this); - m_slots[i]->setMaximumSize(width + 2, height + 2); + m_slots[i]->setMaximumSize(size.width() + 2, size.height() + 2); connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); }); } @@ -131,13 +131,13 @@ bool LoadSaveState::eventFilter(QObject* object, QEvent* event) { if (event->type() == GamepadButtonEvent::Down() || event->type() == GamepadAxisEvent::Type()) { int column = m_currentFocus % 3; int row = m_currentFocus - column; - GBAKey key = GBA_KEY_NONE; + int key = -1; if (event->type() == GamepadButtonEvent::Down()) { - key = static_cast(event)->gbaKey(); + key = static_cast(event)->platformKey(); } else if (event->type() == GamepadAxisEvent::Type()) { GamepadAxisEvent* gae = static_cast(event); if (gae->isNew()) { - key = gae->gbaKey(); + key = gae->platformKey(); } else { return false; } @@ -198,11 +198,17 @@ void LoadSaveState::loadState(int slot) { QDateTime creation; QImage stateImage; - unsigned width, height; - thread->core->desiredVideoDimensions(thread->core, &width, &height); + QSize size = m_controller->screenDimensions(); mStateExtdataItem item; - if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item) && item.size >= static_cast(width * height * 4)) { - stateImage = QImage((uchar*) item.data, width, height, QImage::Format_ARGB32).rgbSwapped(); + if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT, &item)) { + mStateExtdataItem dims; + if (mStateExtdataGet(&extdata, EXTDATA_SCREENSHOT_DIMENSIONS, &dims) && dims.size == sizeof(uint16_t[2])) { + size.setWidth(static_cast(dims.data)[0]); + size.setHeight(static_cast(dims.data)[1]); + } + if (item.size >= static_cast(size.width() * size.height() * 4)) { + stateImage = QImage((uchar*) item.data, size.width(), size.height(), QImage::Format_ARGB32).rgbSwapped(); + } } if (mStateExtdataGet(&extdata, EXTDATA_META_TIME, &item) && item.size == sizeof(uint64_t)) { diff --git a/src/platform/qt/LogController.h b/src/platform/qt/LogController.h index 548be8b4d..6bd4e5707 100644 --- a/src/platform/qt/LogController.h +++ b/src/platform/qt/LogController.h @@ -79,8 +79,8 @@ public slots: private: mLogFilter m_filter; - bool m_logToFile; - bool m_logToStdout; + bool m_logToFile = false; + bool m_logToStdout = false; std::unique_ptr m_logFile; std::unique_ptr m_logStream; diff --git a/src/platform/qt/MapView.cpp b/src/platform/qt/MapView.cpp index ba2255ee9..a00c63c0e 100644 --- a/src/platform/qt/MapView.cpp +++ b/src/platform/qt/MapView.cpp @@ -9,7 +9,7 @@ #include "GBAApp.h" #include "LogController.h" -#include +#include #include #ifdef M_CORE_GBA #include @@ -42,8 +42,8 @@ MapView::MapView(std::shared_ptr controller, QWidget* parent) #ifdef M_CORE_GBA case mPLATFORM_GBA: m_boundary = 2048; - m_ui.tile->setMaxTile(3096); - m_addressBase = BASE_VRAM; + m_ui.tile->setMaxTile(3072); + m_addressBase = GBA_BASE_VRAM; m_addressWidth = 8; m_ui.bgInfo->addCustomProperty("priority", tr("Priority")); m_ui.bgInfo->addCustomProperty("screenBase", tr("Map base")); @@ -119,6 +119,9 @@ void MapView::selectMap(int map) { } m_map = map; m_mapStatus.fill({}); + // Different maps can have different max palette counts; set it to + // 0 immediately to avoid tile lookups with state palette IDs break + m_ui.tile->setPalette(0); updateTiles(true); } @@ -177,33 +180,40 @@ void MapView::updateTilesGBA(bool) { #ifdef M_CORE_GBA if (m_controller->platform() == mPLATFORM_GBA) { uint16_t* io = static_cast(m_controller->thread()->core->board)->memory.io; - int mode = GBARegisterDISPCNTGetMode(io[REG_DISPCNT >> 1]); + int mode = GBARegisterDISPCNTGetMode(io[GBA_REG(DISPCNT)]); if (m_map == 2 && mode > 2) { bitmap = mode == 4 ? 1 : 0; if (mode != 3) { - frame = GBARegisterDISPCNTGetFrameSelect(io[REG_DISPCNT >> 1]); + frame = GBARegisterDISPCNTGetFrameSelect(io[GBA_REG(DISPCNT)]); } } - priority = GBARegisterBGCNTGetPriority(io[(REG_BG0CNT >> 1) + m_map]); + m_boundary = 1024; + m_ui.tile->setMaxTile(1536); + priority = GBARegisterBGCNTGetPriority(io[GBA_REG(BG0CNT) + m_map]); if (mode == 0 || (mode == 1 && m_map != 2)) { offset = QString("%1, %2") - .arg(io[(REG_BG0HOFS >> 1) + (m_map << 1)]) - .arg(io[(REG_BG0VOFS >> 1) + (m_map << 1)]); + .arg(io[GBA_REG(BG0HOFS) + (m_map << 1)]) + .arg(io[GBA_REG(BG0VOFS) + (m_map << 1)]); + + if (!GBARegisterBGCNTIs256Color(io[GBA_REG(BG0CNT) + m_map])) { + m_boundary = 2048; + m_ui.tile->setMaxTile(3072); + } } else if ((mode > 0 && m_map == 2) || (mode == 2 && m_map == 3)) { - int32_t refX = io[(REG_BG2X_LO >> 1) + ((m_map - 2) << 2)]; - refX |= io[(REG_BG2X_HI >> 1) + ((m_map - 2) << 2)] << 16; - int32_t refY = io[(REG_BG2Y_LO >> 1) + ((m_map - 2) << 2)]; - refY |= io[(REG_BG2Y_HI >> 1) + ((m_map - 2) << 2)] << 16; + int32_t refX = io[GBA_REG(BG2X_LO) + ((m_map - 2) << 2)]; + refX |= io[GBA_REG(BG2X_HI) + ((m_map - 2) << 2)] << 16; + int32_t refY = io[GBA_REG(BG2Y_LO) + ((m_map - 2) << 2)]; + refY |= io[GBA_REG(BG2Y_HI) + ((m_map - 2) << 2)] << 16; refX <<= 4; refY <<= 4; refX >>= 4; refY >>= 4; offset = QString("%1\n%2").arg(refX / 65536., 0, 'f', 3).arg(refY / 65536., 0, 'f', 3); transform = QString("%1 %2\n%3 %4") - .arg(io[(REG_BG2PA >> 1) + ((m_map - 2) << 2)] / 256., 3, 'f', 2) - .arg(io[(REG_BG2PB >> 1) + ((m_map - 2) << 2)] / 256., 3, 'f', 2) - .arg(io[(REG_BG2PC >> 1) + ((m_map - 2) << 2)] / 256., 3, 'f', 2) - .arg(io[(REG_BG2PD >> 1) + ((m_map - 2) << 2)] / 256., 3, 'f', 2); + .arg(io[GBA_REG(BG2PA) + ((m_map - 2) << 2)] / 256., 3, 'f', 2) + .arg(io[GBA_REG(BG2PB) + ((m_map - 2) << 2)] / 256., 3, 'f', 2) + .arg(io[GBA_REG(BG2PC) + ((m_map - 2) << 2)] / 256., 3, 'f', 2) + .arg(io[GBA_REG(BG2PD) + ((m_map - 2) << 2)] / 256., 3, 'f', 2); } } diff --git a/src/platform/qt/MemoryAccessLogView.cpp b/src/platform/qt/MemoryAccessLogView.cpp new file mode 100644 index 000000000..3c846b440 --- /dev/null +++ b/src/platform/qt/MemoryAccessLogView.cpp @@ -0,0 +1,148 @@ +/* Copyright (c) 2013-2023 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 "MemoryAccessLogView.h" + +#include + +#include "GBAApp.h" +#include "LogController.h" +#include "utils.h" +#include "VFileDevice.h" + +using namespace QGBA; + +MemoryAccessLogView::MemoryAccessLogView(std::shared_ptr controller, QWidget* parent) + : QWidget(parent) + , m_controller(std::move(controller)) +{ + m_ui.setupUi(this); + + connect(m_ui.browse, &QAbstractButton::clicked, this, &MemoryAccessLogView::selectFile); + connect(m_ui.exportButton, &QAbstractButton::clicked, this, &MemoryAccessLogView::exportFile); + connect(this, &MemoryAccessLogView::loggingChanged, m_ui.start, &QWidget::setDisabled); + connect(this, &MemoryAccessLogView::loggingChanged, m_ui.stop, &QWidget::setEnabled); + connect(this, &MemoryAccessLogView::loggingChanged, m_ui.filename, &QWidget::setDisabled); + connect(this, &MemoryAccessLogView::loggingChanged, m_ui.browse, &QWidget::setDisabled); + + mCore* core = m_controller->thread()->core; + const mCoreMemoryBlock* info; + size_t nBlocks = core->listMemoryBlocks(core, &info); + + QVBoxLayout* regionBox = static_cast(m_ui.regionBox->layout()); + for (size_t i = 0; i < nBlocks; ++i) { + if (!(info[i].flags & mCORE_MEMORY_MAPPED)) { + continue; + } + QCheckBox* region = new QCheckBox(QString::fromUtf8(info[i].longName)); + regionBox->addWidget(region); + + QString name(QString::fromUtf8(info[i].internalName)); + m_regionBoxes[name] = region; + connect(region, &QAbstractButton::toggled, this, [this, name](bool checked) { + updateRegion(name, checked); + }); + } +} + +MemoryAccessLogView::~MemoryAccessLogView() { + stop(); +} + +void MemoryAccessLogView::updateRegion(const QString& internalName, bool checked) { + if (checked) { + m_watchedRegions += internalName; + } else { + m_watchedRegions -= internalName; + } + if (!m_active) { + return; + } + m_regionBoxes[internalName]->setEnabled(false); + m_regionMapping[internalName] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, internalName.toUtf8().constData(), activeFlags()); +} + +void MemoryAccessLogView::start() { + int flags = O_CREAT | O_RDWR; + if (!m_ui.loadExisting->isChecked()) { + flags |= O_TRUNC; + } + VFile* vf = VFileDevice::open(m_ui.filename->text(), flags); + if (!vf) { + // log error + return; + } + mDebuggerAccessLoggerInit(&m_logger); + CoreController::Interrupter interrupter(m_controller); + m_controller->attachDebuggerModule(&m_logger.d); + if (!mDebuggerAccessLoggerOpen(&m_logger, vf, flags)) { + mDebuggerAccessLoggerDeinit(&m_logger); + LOG(QT, ERROR) << tr("Failed to open memory log file"); + return; + } + + m_active = true; + emit loggingChanged(true); + for (const auto& region : m_watchedRegions) { + m_regionBoxes[region]->setEnabled(false); + m_regionMapping[region] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, region.toUtf8().constData(), activeFlags()); + } + interrupter.resume(); + + if (m_watchedRegions.contains(QString("cart0"))) { + m_ui.exportButton->setEnabled(true); + } +} + +void MemoryAccessLogView::stop() { + if (!m_active) { + return; + } + CoreController::Interrupter interrupter(m_controller); + m_controller->detachDebuggerModule(&m_logger.d); + mDebuggerAccessLoggerDeinit(&m_logger); + emit loggingChanged(false); + interrupter.resume(); + + for (const auto& region : m_watchedRegions) { + m_regionBoxes[region]->setEnabled(true); + } + m_ui.exportButton->setEnabled(false); +} + +void MemoryAccessLogView::selectFile() { + QString filename = GBAApp::app()->getSaveFileName(this, tr("Select access log file"), tr("Memory access logs (*.mal)")); + if (!filename.isEmpty()) { + m_ui.filename->setText(filename); + } +} + +mDebuggerAccessLogRegionFlags MemoryAccessLogView::activeFlags() const { + mDebuggerAccessLogRegionFlags loggerFlags = 0; + if (m_ui.logExtra->isChecked()) { + loggerFlags = mDebuggerAccessLogRegionFlagsFillHasExBlock(loggerFlags); + } + return loggerFlags; +} + +void MemoryAccessLogView::exportFile() { + if (!m_regionMapping.contains("cart0")) { + return; + } + + QString filename = GBAApp::app()->getSaveFileName(this, tr("Select access log file"), romFilters(false, m_controller->platform(), true)); + if (filename.isEmpty()) { + return; + } + VFile* vf = VFileDevice::open(filename, O_CREAT | O_TRUNC | O_WRONLY); + if (!vf) { + // log error + return; + } + + CoreController::Interrupter interrupter(m_controller); + mDebuggerAccessLoggerCreateShadowFile(&m_logger, m_regionMapping[QString("cart0")], vf, 0); + vf->close(vf); +} diff --git a/src/platform/qt/MemoryAccessLogView.h b/src/platform/qt/MemoryAccessLogView.h new file mode 100644 index 000000000..ffe31cc43 --- /dev/null +++ b/src/platform/qt/MemoryAccessLogView.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include +#include + +#include + +#include "CoreController.h" + +#include + +#include "ui_MemoryAccessLogView.h" + +namespace QGBA { + +class MemoryAccessLogView : public QWidget { +Q_OBJECT + +public: + MemoryAccessLogView(std::shared_ptr controller, QWidget* parent = nullptr); + ~MemoryAccessLogView(); + +private slots: + void updateRegion(const QString& internalName, bool enable); + void selectFile(); + + void start(); + void stop(); + + void exportFile(); + +signals: + void loggingChanged(bool active); + +private: + Ui::MemoryAccessLogView m_ui; + + std::shared_ptr m_controller; + QSet m_watchedRegions; + QHash m_regionBoxes; + QHash m_regionMapping; + struct mDebuggerAccessLogger m_logger{}; + bool m_active = false; + + mDebuggerAccessLogRegionFlags activeFlags() const; +}; + +} diff --git a/src/platform/qt/MemoryAccessLogView.ui b/src/platform/qt/MemoryAccessLogView.ui new file mode 100644 index 000000000..fe9450f53 --- /dev/null +++ b/src/platform/qt/MemoryAccessLogView.ui @@ -0,0 +1,132 @@ + + + QGBA::MemoryAccessLogView + + + + 0 + 0 + 385 + 380 + + + + Memory access logging + + + + QLayout::SetFixedSize + + + + + Log file + + + + + + + + + Browse + + + + + + + Log additional information (uses 3× space) + + + + + + + Load existing file if present + + + true + + + + + + + + + + Regions + + + + + + + + false + + + Export ROM snapshot + + + + + + + Start + + + + + + + false + + + Stop + + + + + + + + + start + clicked() + QGBA::MemoryAccessLogView + start() + + + 97 + 357 + + + 192 + 189 + + + + + stop + clicked() + QGBA::MemoryAccessLogView + stop() + + + 287 + 357 + + + 192 + 189 + + + + + + start() + stop() + + diff --git a/src/platform/qt/MemoryDump.cpp b/src/platform/qt/MemoryDump.cpp index 982353ee2..59cef31be 100644 --- a/src/platform/qt/MemoryDump.cpp +++ b/src/platform/qt/MemoryDump.cpp @@ -13,7 +13,7 @@ using namespace QGBA; MemoryDump::MemoryDump(std::shared_ptr controller, QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) - , m_controller(controller) + , m_controller(std::move(controller)) { m_ui.setupUi(this); @@ -117,4 +117,4 @@ QByteArray MemoryDump::serialize() { } return mem; -} \ No newline at end of file +} diff --git a/src/platform/qt/MemoryModel.cpp b/src/platform/qt/MemoryModel.cpp index 1777fddd0..538ce2c51 100644 --- a/src/platform/qt/MemoryModel.cpp +++ b/src/platform/qt/MemoryModel.cpp @@ -321,7 +321,7 @@ QString MemoryModel::decodeText(const QByteArray& bytes) { text = QString::fromUtf8(array); } else { for (uint8_t c : bytes) { - text.append((uchar) c); + text.append(QChar(c)); } } return text; @@ -488,7 +488,7 @@ void MemoryModel::paintEvent(QPaintEvent*) { for (int i = 0; i < text.size() && i < m_align; ++i) { const QChar c = text.at(i); const QPointF location(viewport()->size().width() - (16 - x - i) * m_margins.right() / 17.0 - m_letterWidth * 0.5, yp); - if (c < 256) { + if (c.unicode() < 256) { painter.drawStaticText(location, m_staticLatin1[c.cell()]); } else { painter.drawText(location, c); diff --git a/src/platform/qt/MemorySearch.cpp b/src/platform/qt/MemorySearch.cpp index 8589f9cfe..34f87fe14 100644 --- a/src/platform/qt/MemorySearch.cpp +++ b/src/platform/qt/MemorySearch.cpp @@ -27,8 +27,6 @@ MemorySearch::MemorySearch(std::shared_ptr controller, QWidget* connect(m_ui.numHex, &QPushButton::clicked, this, &MemorySearch::refresh); connect(m_ui.numDec, &QPushButton::clicked, this, &MemorySearch::refresh); connect(m_ui.viewMem, &QPushButton::clicked, this, &MemorySearch::openMemory); - - connect(controller.get(), &CoreController::stopping, this, &QWidget::close); } MemorySearch::~MemorySearch() { @@ -178,7 +176,7 @@ void MemorySearch::refresh() { mCoreMemorySearchResult* result = mCoreMemorySearchResultsGetPointer(&m_results, i); QTableWidgetItem* item = new QTableWidgetItem(QString("%1").arg(result->address, 8, 16, QChar('0'))); m_ui.results->setItem(i, 0, item); - QTableWidgetItem* type; + QTableWidgetItem* type = nullptr; QByteArray string; if (result->type == mCORE_MEMORY_SEARCH_INT && m_ui.numHex->isChecked()) { switch (result->width) { @@ -213,7 +211,12 @@ void MemorySearch::refresh() { string.append(core->rawRead8(core, result->address + i, result->segment)); } item = new QTableWidgetItem(QLatin1String(string)); // TODO + break; + case mCORE_MEMORY_SEARCH_GUESS: + item = nullptr; + break; } + Q_ASSERT(item); } QString divisor; if (result->guessDivisor > 1) { @@ -231,7 +234,12 @@ void MemorySearch::refresh() { break; case mCORE_MEMORY_SEARCH_STRING: type = new QTableWidgetItem("string"); + break; + case mCORE_MEMORY_SEARCH_GUESS: + break; } + Q_ASSERT(type); + m_ui.results->setItem(i, 1, item); m_ui.results->setItem(i, 2, type); m_ui.opDelta->setEnabled(true); diff --git a/src/platform/qt/MemoryView.cpp b/src/platform/qt/MemoryView.cpp index c740b4dca..4383867e0 100644 --- a/src/platform/qt/MemoryView.cpp +++ b/src/platform/qt/MemoryView.cpp @@ -153,8 +153,6 @@ MemoryView::MemoryView(std::shared_ptr controller, QWidget* pare connect(m_ui.hexfield, &MemoryModel::selectionChanged, this, &MemoryView::updateSelection); connect(m_ui.saveRange, &QAbstractButton::clicked, this, &MemoryView::saveRange); - connect(controller.get(), &CoreController::stopping, this, &QWidget::close); - connect(controller.get(), &CoreController::frameAvailable, this, &MemoryView::update); connect(controller.get(), &CoreController::paused, this, &MemoryView::update); connect(controller.get(), &CoreController::stateLoaded, this, &MemoryView::update); diff --git a/src/platform/qt/MultiplayerController.cpp b/src/platform/qt/MultiplayerController.cpp index f44323603..7ded956a4 100644 --- a/src/platform/qt/MultiplayerController.cpp +++ b/src/platform/qt/MultiplayerController.cpp @@ -6,6 +6,7 @@ #include "MultiplayerController.h" #include "CoreController.h" +#include "LogController.h" #ifdef M_CORE_GBA #include @@ -18,21 +19,10 @@ using namespace QGBA; -#ifdef M_CORE_GB -MultiplayerController::Player::Player(CoreController* coreController, GBSIOLockstepNode* gbNode) +MultiplayerController::Player::Player(CoreController* coreController) : controller(coreController) { - node.gb = gbNode; } -#endif - -#ifdef M_CORE_GBA -MultiplayerController::Player::Player(CoreController* coreController, GBASIOLockstepNode* gbaNode) - : controller(coreController) -{ - node.gba = gbaNode; -} -#endif int MultiplayerController::Player::id() const { switch (controller->platform()) { @@ -67,7 +57,7 @@ MultiplayerController::MultiplayerController() { }; m_lockstep.signal = [](mLockstep* lockstep, unsigned mask) { MultiplayerController* controller = static_cast(lockstep->context); - Player* player = &controller->m_players[0]; + Player* player = controller->player(0); bool woke = false; player->waitMask &= ~mask; if (!player->waitMask && player->awake < 1) { @@ -79,7 +69,7 @@ MultiplayerController::MultiplayerController() { }; m_lockstep.wait = [](mLockstep* lockstep, unsigned mask) { MultiplayerController* controller = static_cast(lockstep->context); - Player* player = &controller->m_players[0]; + Player* player = controller->player(0); bool slept = false; player->waitMask |= mask; if (player->awake > 0) { @@ -102,6 +92,10 @@ MultiplayerController::MultiplayerController() { if (!id) { for (int i = 1; i < controller->m_players.count(); ++i) { player = controller->player(i); + if (player->node.gba->d.p->mode > SIO_MULTI) { + player->controller->setSync(true); + continue; + } player->controller->setSync(false); player->cyclesPosted += cycles; if (player->awake < 1) { @@ -214,8 +208,10 @@ MultiplayerController::~MultiplayerController() { } bool MultiplayerController::attachGame(CoreController* controller) { - if (m_lockstep.attached == MAX_GBAS) { - return false; + QList interrupters; + interrupters.append(controller); + for (Player& p : m_pids.values()) { + interrupters.append(p.controller); } if (m_lockstep.attached == 0) { @@ -233,6 +229,9 @@ bool MultiplayerController::attachGame(CoreController* controller) { default: return false; } + m_platform = controller->platform(); + } else if (controller->platform() != m_platform) { + return false; } mCoreThread* thread = controller->thread(); @@ -240,43 +239,79 @@ bool MultiplayerController::attachGame(CoreController* controller) { return false; } + Player player{controller}; switch (controller->platform()) { #ifdef M_CORE_GBA case mPLATFORM_GBA: { + if (m_lockstep.attached >= MAX_GBAS) { + return false; + } + GBA* gba = static_cast(thread->core->board); GBASIOLockstepNode* node = new GBASIOLockstepNode; GBASIOLockstepNodeCreate(node); GBASIOLockstepAttachNode(&m_gbaLockstep, node); - m_players.append({controller, node}); + player.node.gba = node; GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI); GBASIOSetDriver(&gba->sio, &node->d, SIO_NORMAL_32); - - emit gameAttached(); - return true; + break; } #endif #ifdef M_CORE_GB case mPLATFORM_GB: { + if (m_lockstep.attached >= 2) { + return false; + } + GB* gb = static_cast(thread->core->board); GBSIOLockstepNode* node = new GBSIOLockstepNode; GBSIOLockstepNodeCreate(node); GBSIOLockstepAttachNode(&m_gbLockstep, node); - m_players.append({controller, node}); + player.node.gb = node; GBSIOSetDriver(&gb->sio, &node->d); - - emit gameAttached(); - return true; + break; } #endif default: - break; + return false; } - return false; + QPair path(controller->path(), controller->baseDirectory()); + int claimed = m_claimed[path]; + + int saveId = 0; + mCoreConfigGetIntValue(&controller->thread()->core->config, "savePlayerId", &saveId); + + if (claimed) { + player.saveId = 0; + for (int i = 0; i < MAX_GBAS; ++i) { + if (claimed & (1 << i)) { + continue; + } + player.saveId = i + 1; + break; + } + if (!player.saveId) { + LOG(QT, ERROR) << "Couldn't find available save ID"; + player.saveId = 1; + } + } else if (saveId) { + player.saveId = saveId; + } else { + player.saveId = 1; + } + m_claimed[path] |= 1 << (player.saveId - 1); + + m_pids.insert(m_nextPid, player); + ++m_nextPid; + fixOrder(); + + emit gameAttached(); + return true; } void MultiplayerController::detachGame(CoreController* controller) { @@ -289,8 +324,18 @@ void MultiplayerController::detachGame(CoreController* controller) { } QList interrupters; + int pid = -1; for (int i = 0; i < m_players.count(); ++i) { - interrupters.append(m_players[i].controller); + Player* p = player(i); + if (!p) { + LOG(QT, ERROR) << tr("Trying to detach a multiplayer player that's not attached"); + return; + } + CoreController* playerController = p->controller; + if (playerController == controller) { + pid = m_players[i]; + } + interrupters.append(playerController); } switch (controller->platform()) { #ifdef M_CORE_GBA @@ -322,24 +367,55 @@ void MultiplayerController::detachGame(CoreController* controller) { break; } - for (int i = 0; i < m_players.count(); ++i) { - if (m_players[i].controller == controller) { - m_players.removeAt(i); - break; + // TODO: This might change if we replace the ROM--make sure to handle this properly + QPair path(controller->path(), controller->baseDirectory()); + Player& p = m_pids.find(pid).value(); + if (!p.saveId) { + LOG(QT, ERROR) << "Clearing invalid save ID"; + } else { + m_claimed[path] &= ~(1 << (p.saveId - 1)); + if (!m_claimed[path]) { + m_claimed.remove(path); } } + + m_pids.remove(pid); + if (m_pids.size() == 0) { + m_platform = mPLATFORM_NONE; + } else { + fixOrder(); + } emit gameDetached(); } -int MultiplayerController::playerId(CoreController* controller) { +int MultiplayerController::playerId(CoreController* controller) const { for (int i = 0; i < m_players.count(); ++i) { - if (m_players[i].controller == controller) { + const Player* p = player(i); + if (!p) { + LOG(QT, ERROR) << tr("Trying to get player ID for a multiplayer player that's not attached"); + return -1; + } + if (p->controller == controller) { return i; } } return -1; } +int MultiplayerController::saveId(CoreController* controller) const { + for (int i = 0; i < m_players.count(); ++i) { + const Player* p = player(i); + if (!p) { + LOG(QT, ERROR) << tr("Trying to get save ID for a multiplayer player that's not attached"); + return -1; + } + if (p->controller == controller) { + return p->saveId; + } + } + return -1; +} + int MultiplayerController::attached() { int num; num = m_lockstep.attached; @@ -347,27 +423,52 @@ int MultiplayerController::attached() { } MultiplayerController::Player* MultiplayerController::player(int id) { - Player* player = &m_players[id]; - switch (player->controller->platform()) { + if (id >= m_players.size()) { + return nullptr; + } + int pid = m_players[id]; + auto iter = m_pids.find(pid); + if (iter == m_pids.end()) { + return nullptr; + } + return &iter.value(); +} + +const MultiplayerController::Player* MultiplayerController::player(int id) const { + if (id >= m_players.size()) { + return nullptr; + } + int pid = m_players[id]; + auto iter = m_pids.find(pid); + if (iter == m_pids.end()) { + return nullptr; + } + return &iter.value(); +} + +void MultiplayerController::fixOrder() { + m_players.clear(); + m_players = m_pids.keys(); + std::sort(m_players.begin(), m_players.end()); + switch (m_platform) { #ifdef M_CORE_GBA case mPLATFORM_GBA: - if (player->node.gba->id != id) { - std::sort(m_players.begin(), m_players.end()); - player = &m_players[id]; + for (int pid : m_pids.keys()) { + Player& p = m_pids.find(pid).value(); + GBA* gba = static_cast(p.controller->thread()->core->board); + GBASIOLockstepNode* node = reinterpret_cast(gba->sio.drivers.multiplayer); + m_players[node->id] = pid; } break; #endif #ifdef M_CORE_GB case mPLATFORM_GB: - if (player->node.gb->id != id) { + if (player(0)->node.gb->id == 1) { std::swap(m_players[0], m_players[1]); - player = &m_players[id]; } break; #endif case mPLATFORM_NONE: break; } - - return player; } diff --git a/src/platform/qt/MultiplayerController.h b/src/platform/qt/MultiplayerController.h index 5ad6124db..b5582319f 100644 --- a/src/platform/qt/MultiplayerController.h +++ b/src/platform/qt/MultiplayerController.h @@ -5,10 +5,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once +#include #include #include #include +#include #include #ifdef M_CORE_GBA #include @@ -37,7 +39,8 @@ public: void detachGame(CoreController*); int attached(); - int playerId(CoreController*); + int playerId(CoreController*) const; + int saveId(CoreController*) const; signals: void gameAttached(); @@ -49,12 +52,7 @@ private: GBASIOLockstepNode* gba; }; struct Player { -#ifdef M_CORE_GB - Player(CoreController* controller, GBSIOLockstepNode* node); -#endif -#ifdef M_CORE_GBA - Player(CoreController* controller, GBASIOLockstepNode* node); -#endif + Player(CoreController* controller); int id() const; bool operator<(const Player&) const; @@ -64,9 +62,12 @@ private: int awake = 1; int32_t cyclesPosted = 0; unsigned waitMask = 0; + int saveId = 1; }; Player* player(int id); + const Player* player(int id) const; + void fixOrder(); union { mLockstep m_lockstep; @@ -77,8 +78,13 @@ private: GBASIOLockstep m_gbaLockstep; #endif }; - QList m_players; + + mPlatform m_platform = mPLATFORM_NONE; + int m_nextPid = 0; + QHash m_pids; + QList m_players; QMutex m_lock; + QHash, int> m_claimed; }; } diff --git a/src/platform/qt/ObjView.cpp b/src/platform/qt/ObjView.cpp index f1b605c0d..f4482aba6 100644 --- a/src/platform/qt/ObjView.cpp +++ b/src/platform/qt/ObjView.cpp @@ -157,7 +157,7 @@ void ObjView::updateTilesGBA(bool force) { m_ui.w->setText(QString::number(newInfo.width * 8)); m_ui.h->setText(QString::number(newInfo.height * 8)); - m_ui.address->setText(tr("0x%0").arg(BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0'))); + m_ui.address->setText(tr("0x%0").arg(GBA_BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0'))); m_ui.priority->setText(QString::number(newInfo.priority)); m_ui.flippedH->setChecked(newInfo.hflip); m_ui.flippedV->setChecked(newInfo.vflip); diff --git a/src/platform/qt/OpenGLBug.cpp b/src/platform/qt/OpenGLBug.cpp index df007c1cb..089d7d754 100644 --- a/src/platform/qt/OpenGLBug.cpp +++ b/src/platform/qt/OpenGLBug.cpp @@ -31,6 +31,17 @@ bool glContextHasBug(OpenGLBug bug) { case OpenGLBug::GLTHREAD_BLOCKS_SWAP: return version.contains(" Mesa "); + case OpenGLBug::IG4ICD_CRASH: +#ifdef Q_OS_WIN + if (vendor != "Intel") { + return false; + } + if (renderer == "Intel Pineview Platform") { + return true; + } +#endif + return false; + default: return false; } diff --git a/src/platform/qt/OpenGLBug.h b/src/platform/qt/OpenGLBug.h index 5b5bc7736..f63fe282e 100644 --- a/src/platform/qt/OpenGLBug.h +++ b/src/platform/qt/OpenGLBug.h @@ -10,6 +10,7 @@ namespace QGBA { enum class OpenGLBug { CROSS_THREAD_FLUSH, // mgba.io/i/2761 GLTHREAD_BLOCKS_SWAP, // mgba.io/i/2767 + IG4ICD_CRASH, // mgba.io/i/2136 }; bool glContextHasBug(OpenGLBug); diff --git a/src/platform/qt/Override.h b/src/platform/qt/Override.h index 2ff209d8c..bf28aa755 100644 --- a/src/platform/qt/Override.h +++ b/src/platform/qt/Override.h @@ -14,9 +14,9 @@ class Override { public: virtual ~Override() {} - virtual void apply(struct mCore*) = 0; virtual void identify(const struct mCore*) = 0; virtual void save(struct Configuration*) const = 0; + virtual const void* raw() const = 0; }; } diff --git a/src/platform/qt/PaletteView.cpp b/src/platform/qt/PaletteView.cpp index 7d70c9741..de09c270a 100644 --- a/src/platform/qt/PaletteView.cpp +++ b/src/platform/qt/PaletteView.cpp @@ -19,7 +19,7 @@ #ifdef M_CORE_GB #include #endif -#include +#include #include using namespace QGBA; @@ -60,8 +60,6 @@ PaletteView::PaletteView(std::shared_ptr controller, QWidget* pa connect(m_ui.objGrid, &Swatch::indexPressed, [this, count] (int index) { selectIndex(index + count); }); connect(m_ui.exportBG, &QAbstractButton::clicked, [this, count] () { exportPalette(0, count); }); connect(m_ui.exportOBJ, &QAbstractButton::clicked, [this, count] () { exportPalette(count, count); }); - - connect(controller.get(), &CoreController::stopping, this, &QWidget::close); } void PaletteView::updatePalette() { @@ -145,9 +143,9 @@ void PaletteView::exportPalette(int start, int length) { return; } if (filename.endsWith(".pal", Qt::CaseInsensitive)) { - exportPaletteRIFF(vf, length, &static_cast(m_controller->thread()->core->board)->video.palette[start]); + mPaletteExportRIFF(vf, length, &static_cast(m_controller->thread()->core->board)->video.palette[start]); } else if (filename.endsWith(".act", Qt::CaseInsensitive)) { - exportPaletteACT(vf, length, &static_cast(m_controller->thread()->core->board)->video.palette[start]); + mPaletteExportACT(vf, length, &static_cast(m_controller->thread()->core->board)->video.palette[start]); } vf->close(vf); } diff --git a/src/platform/qt/PlacementControl.cpp b/src/platform/qt/PlacementControl.cpp index fc031d019..0011dff5f 100644 --- a/src/platform/qt/PlacementControl.cpp +++ b/src/platform/qt/PlacementControl.cpp @@ -15,7 +15,7 @@ using namespace QGBA; PlacementControl::PlacementControl(std::shared_ptr controller, QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) - , m_controller(controller) + , m_controller(std::move(controller)) { m_ui.setupUi(this); diff --git a/src/platform/qt/ROMInfo.cpp b/src/platform/qt/ROMInfo.cpp index f690982c4..473918f26 100644 --- a/src/platform/qt/ROMInfo.cpp +++ b/src/platform/qt/ROMInfo.cpp @@ -62,4 +62,11 @@ ROMInfo::ROMInfo(std::shared_ptr controller, QWidget* parent) m_ui.crc->setText(tr("(unknown)")); m_ui.name->setText(tr("(unknown)")); } + + QString savePath = controller->savePath(); + if (!savePath.isEmpty()) { + m_ui.savefile->setText(savePath); + } else { + m_ui.savefile->setText(tr("(unknown)")); + } } diff --git a/src/platform/qt/ROMInfo.ui b/src/platform/qt/ROMInfo.ui index c458a7a07..727cff032 100644 --- a/src/platform/qt/ROMInfo.ui +++ b/src/platform/qt/ROMInfo.ui @@ -108,6 +108,20 @@ + + + + Save file: + + + + + + + {SAVEFILE} + + + diff --git a/src/platform/qt/ReportView.cpp b/src/platform/qt/ReportView.cpp index 494f45a64..04944ef5c 100644 --- a/src/platform/qt/ReportView.cpp +++ b/src/platform/qt/ReportView.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include "CoreController.h" @@ -127,6 +127,7 @@ void ReportView::generateReport() { swReport << QString("Build architecture: %1").arg(QSysInfo::buildCpuArchitecture()); swReport << QString("Run architecture: %1").arg(QSysInfo::currentCpuArchitecture()); swReport << QString("Qt version: %1").arg(QLatin1String(qVersion())); + swReport << QString("Qt QPA platform: %1").arg(QGuiApplication::platformName()); #ifdef USE_FFMPEG QStringList libavVers; libavVers << QLatin1String(LIBAVCODEC_IDENT); @@ -314,10 +315,8 @@ void ReportView::generateReport() { } else { windowReport << QString("ROM open: No"); } -#ifdef BUILD_SDL InputController* input = window->inputController(); - windowReport << QString("Active gamepad: %1").arg(input->gamepad(SDL_BINDING_BUTTON)); -#endif + windowReport << QString("Active gamepad: %1").arg(input->gamepadIndex()); windowReport << QString("Configuration: %1").arg(configs.indexOf(config) + 1); addReport(QString("Window %1").arg(winId), windowReport.join('\n')); } @@ -477,9 +476,8 @@ void ReportView::addGLInfo(QStringList& report) { } void ReportView::addGamepadInfo(QStringList& report) { -#ifdef BUILD_SDL InputController* input = GBAApp::app()->windows()[0]->inputController(); - QStringList gamepads = input->connectedGamepads(SDL_BINDING_BUTTON); + QStringList gamepads = input->connectedGamepads(); report << QString("Connected gamepads: %1").arg(gamepads.size()); int i = 0; for (const auto& gamepad : gamepads) { @@ -490,10 +488,9 @@ void ReportView::addGamepadInfo(QStringList& report) { i = 0; for (Window* window : GBAApp::app()->windows()) { ++i; - report << QString("Window %1 gamepad: %2").arg(i).arg(window->inputController()->gamepad(SDL_BINDING_BUTTON)); + report << QString("Window %1 gamepad: %2").arg(i).arg(window->inputController()->gamepadIndex()); } } -#endif } void ReportView::addROMInfo(QStringList& report, CoreController* controller) { diff --git a/src/platform/qt/SaveConverter.cpp b/src/platform/qt/SaveConverter.cpp index fd242af98..44e061c8f 100644 --- a/src/platform/qt/SaveConverter.cpp +++ b/src/platform/qt/SaveConverter.cpp @@ -27,9 +27,8 @@ using namespace QGBA; -SaveConverter::SaveConverter(std::shared_ptr controller, QWidget* parent) +SaveConverter::SaveConverter(QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint) - , m_controller(controller) { m_ui.setupUi(this); @@ -197,20 +196,25 @@ void SaveConverter::detectFromSavestate(VFile* vf) { void SaveConverter::detectFromSize(std::shared_ptr vf) { #ifdef M_CORE_GBA switch (vf->size()) { - case SIZE_CART_SRAM: + case GBA_SIZE_SRAM: + case GBA_SIZE_SRAM + 16: m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, vf}); break; - case SIZE_CART_FLASH512: + case GBA_SIZE_FLASH512: + case GBA_SIZE_FLASH512 + 16: m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, vf}); break; - case SIZE_CART_FLASH1M: + case GBA_SIZE_FLASH1M: + case GBA_SIZE_FLASH1M + 16: m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, vf}); break; - case SIZE_CART_EEPROM: + case GBA_SIZE_EEPROM: + case GBA_SIZE_EEPROM + 16: m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, vf, Endian::LITTLE}); m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, vf, Endian::BIG}); break; - case SIZE_CART_EEPROM512: + case GBA_SIZE_EEPROM512: + case GBA_SIZE_EEPROM512 + 16: m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, vf, Endian::LITTLE}); m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, vf, Endian::BIG}); break; @@ -267,13 +271,13 @@ void SaveConverter::detectFromHeaders(std::shared_ptr vf) { if (data) { QByteArray bytes = QByteArray::fromRawData(static_cast(data), size); bytes.data(); // Trigger a deep copy before we delete the backing - if (size == SIZE_CART_FLASH1M) { + if (size == GBA_SIZE_FLASH1M) { m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, std::make_shared(bytes), Endian::NONE, Container::SHARKPORT}); } else { - m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared(bytes.left(SIZE_CART_SRAM)), Endian::NONE, Container::SHARKPORT}); - m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, std::make_shared(bytes.left(SIZE_CART_FLASH512)), Endian::NONE, Container::SHARKPORT}); - m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared(bytes.left(SIZE_CART_EEPROM)), Endian::BIG, Container::SHARKPORT}); - m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared(bytes.left(SIZE_CART_EEPROM512)), Endian::BIG, Container::SHARKPORT}); + m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared(bytes.left(GBA_SIZE_SRAM)), Endian::NONE, Container::SHARKPORT}); + m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, std::make_shared(bytes.left(GBA_SIZE_FLASH512)), Endian::NONE, Container::SHARKPORT}); + m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared(bytes.left(GBA_SIZE_EEPROM)), Endian::BIG, Container::SHARKPORT}); + m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared(bytes.left(GBA_SIZE_EEPROM512)), Endian::BIG, Container::SHARKPORT}); } free(data); } @@ -284,21 +288,21 @@ void SaveConverter::detectFromHeaders(std::shared_ptr vf) { QByteArray bytes = QByteArray::fromRawData(static_cast(data), size); bytes.data(); // Trigger a deep copy before we delete the backing switch (size) { - case SIZE_CART_FLASH1M: + case GBA_SIZE_FLASH1M: m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, std::make_shared(bytes), Endian::NONE, Container::GSV}); break; - case SIZE_CART_FLASH512: + case GBA_SIZE_FLASH512: m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH512, std::make_shared(bytes), Endian::NONE, Container::GSV}); m_validSaves.append(AnnotatedSave{SAVEDATA_FLASH1M, std::make_shared(bytes), Endian::NONE, Container::GSV}); break; - case SIZE_CART_SRAM: - m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared(bytes.left(SIZE_CART_SRAM)), Endian::NONE, Container::GSV}); + case GBA_SIZE_SRAM: + m_validSaves.append(AnnotatedSave{SAVEDATA_SRAM, std::make_shared(bytes.left(GBA_SIZE_SRAM)), Endian::NONE, Container::GSV}); break; - case SIZE_CART_EEPROM: - m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared(bytes.left(SIZE_CART_EEPROM)), Endian::BIG, Container::GSV}); + case GBA_SIZE_EEPROM: + m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM, std::make_shared(bytes.left(GBA_SIZE_EEPROM)), Endian::BIG, Container::GSV}); break; - case SIZE_CART_EEPROM512: - m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared(bytes.left(SIZE_CART_EEPROM512)), Endian::BIG, Container::GSV}); + case GBA_SIZE_EEPROM512: + m_validSaves.append(AnnotatedSave{SAVEDATA_EEPROM512, std::make_shared(bytes.left(GBA_SIZE_EEPROM512)), Endian::BIG, Container::GSV}); break; } free(data); @@ -478,6 +482,9 @@ SaveConverter::AnnotatedSave::operator QString() const { default: break; } + if ((size & 0xFF) == 0x10) { + typeFormat += QCoreApplication::translate("QGBA::SaveConverter", " + RTC"); + } break; #endif #ifdef M_CORE_GB @@ -615,9 +622,23 @@ QList SaveConverter::AnnotatedSave::possibleConver } break; default: + if (size & 0xFF) { + AnnotatedSave noRtc = same; + noRtc.size &= ~0xFF; + possible.append(noRtc); + } break; } break; +#endif +#ifdef M_CORE_GBA + case mPLATFORM_GBA: + if ((size & 0xFF) == 0x10) { + AnnotatedSave noRtc = same; + noRtc.size &= ~0xFF; + possible.append(noRtc); + } + break; #endif default: break; @@ -650,7 +671,7 @@ QByteArray SaveConverter::AnnotatedSave::convertTo(const SaveConverter::Annotate } converted.resize(target.size); buffer = backing->readAll(); - for (int i = 0; i < size; i += 8) { + for (int i = 0; i < (size & ~0xFF); i += 8) { uint64_t word; const uint64_t* in = reinterpret_cast(buffer.constData()); uint64_t* out = reinterpret_cast(converted.data()); @@ -661,6 +682,9 @@ QByteArray SaveConverter::AnnotatedSave::convertTo(const SaveConverter::Annotate default: break; } + if (endianness == target.endianness && size > target.size) { + converted = backing->read(target.size); + } break; #endif #ifdef M_CORE_GB @@ -711,6 +735,9 @@ QByteArray SaveConverter::AnnotatedSave::convertTo(const SaveConverter::Annotate } break; default: + if (endianness == target.endianness && size > target.size) { + converted = backing->read(target.size); + } break; } break; diff --git a/src/platform/qt/SaveConverter.h b/src/platform/qt/SaveConverter.h index 6b9f3df62..2fa133071 100644 --- a/src/platform/qt/SaveConverter.h +++ b/src/platform/qt/SaveConverter.h @@ -31,7 +31,7 @@ class SaveConverter : public QDialog { Q_OBJECT public: - SaveConverter(std::shared_ptr controller, QWidget* parent = nullptr); + SaveConverter(QWidget* parent = nullptr); static mPlatform getStatePlatform(VFile*); static QByteArray getState(VFile*, mPlatform); @@ -100,7 +100,6 @@ private: Ui::SaveConverter m_ui; - std::shared_ptr m_controller; QList m_validSaves; QList m_validOutputs; }; diff --git a/src/platform/qt/SensorView.cpp b/src/platform/qt/SensorView.cpp index 22c2f5f3f..ba1cf0ce9 100644 --- a/src/platform/qt/SensorView.cpp +++ b/src/platform/qt/SensorView.cpp @@ -6,7 +6,8 @@ #include "SensorView.h" #include "CoreController.h" -#include "GamepadAxisEvent.h" +#include "input/GamepadAxisEvent.h" +#include "input/InputDriver.h" #include "InputController.h" #include "utils.h" @@ -47,14 +48,20 @@ SensorView::SensorView(InputController* input, QWidget* parent) m_timer.start(); } - jiggerer(m_ui.tiltSetX, &InputController::registerTiltAxisX); - jiggerer(m_ui.tiltSetY, &InputController::registerTiltAxisY); - jiggerer(m_ui.gyroSetX, &InputController::registerGyroAxisX); - jiggerer(m_ui.gyroSetY, &InputController::registerGyroAxisY); + jiggerer(m_ui.tiltSetX, &InputDriver::registerTiltAxisX); + jiggerer(m_ui.tiltSetY, &InputDriver::registerTiltAxisY); + jiggerer(m_ui.gyroSetX, &InputDriver::registerGyroAxisX); + jiggerer(m_ui.gyroSetY, &InputDriver::registerGyroAxisY); - m_ui.gyroSensitivity->setValue(m_input->gyroSensitivity() / 1e8f); + InputDriver* sensorDriver = m_input->sensorDriver(); + if (sensorDriver) { + m_ui.gyroSensitivity->setValue(sensorDriver->gyroSensitivity() / 1e8f); + } connect(m_ui.gyroSensitivity, static_cast(&QDoubleSpinBox::valueChanged), [this](double value) { - m_input->setGyroSensitivity(value * 1e8f); + InputDriver* sensorDriver = m_input->sensorDriver(); + if (sensorDriver) { + sensorDriver->setGyroSensitivity(value * 1e8f); + } }); m_input->stealFocus(this); connect(m_input, &InputController::luminanceValueChanged, this, &SensorView::luminanceValueChanged); @@ -84,7 +91,7 @@ void SensorView::setController(std::shared_ptr controller) { }); } -void SensorView::jiggerer(QAbstractButton* button, void (InputController::*setter)(int)) { +void SensorView::jiggerer(QAbstractButton* button, void (InputDriver::*setter)(int)) { connect(button, &QAbstractButton::toggled, [this, button, setter](bool checked) { if (!checked) { m_button = nullptr; @@ -115,7 +122,10 @@ bool SensorView::eventFilter(QObject*, QEvent* event) { m_button->removeEventFilter(this); m_button->clearFocus(); m_button->setChecked(false); - (m_input->*m_setter)(gae->axis()); + InputDriver* sensorDriver = m_input->sensorDriver(); + if (sensorDriver) { + (sensorDriver->*m_setter)(gae->axis()); + } m_button = nullptr; } return true; diff --git a/src/platform/qt/SensorView.h b/src/platform/qt/SensorView.h index 5ccc40ec8..2bb5047cd 100644 --- a/src/platform/qt/SensorView.h +++ b/src/platform/qt/SensorView.h @@ -21,6 +21,7 @@ class ConfigController; class CoreController; class GamepadAxisEvent; class InputController; +class InputDriver; class SensorView : public QDialog { Q_OBJECT @@ -43,14 +44,14 @@ private: Ui::SensorView m_ui; QAbstractButton* m_button = nullptr; - void (InputController::*m_setter)(int); + void (InputDriver::*m_setter)(int); std::shared_ptr m_controller; InputController* m_input; mRotationSource* m_rotation; QTimer m_timer; - void jiggerer(QAbstractButton*, void (InputController::*)(int)); + void jiggerer(QAbstractButton*, void (InputDriver::*)(int)); }; } diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index cba481dc8..7f0fef53f 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -25,6 +25,10 @@ #include #include +#ifdef BUILD_SDL +#include "platform/sdl/sdl-events.h" +#endif + using namespace QGBA; SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, LogController* logController, QWidget* parent) @@ -47,7 +51,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC #ifdef M_CORE_GB m_pageIndex[Page::GB] = 9; - for (auto model : GameBoy::modelList()) { + for (auto& model : GameBoy::modelList()) { m_ui.gbModel->addItem(GameBoy::modelName(model), model); m_ui.sgbModel->addItem(GameBoy::modelName(model), model); m_ui.cgbModel->addItem(GameBoy::modelName(model), model); @@ -139,6 +143,9 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC connect(m_ui.cheatsBrowse, &QAbstractButton::pressed, [this] () { selectPath(m_ui.cheatsPath, m_ui.cheatsSameDir); }); + connect(m_ui.bgImageBrowse, &QAbstractButton::pressed, [this] () { + selectImage(m_ui.bgImage); + }); connect(m_ui.clearCache, &QAbstractButton::pressed, this, &SettingsView::libraryCleared); // TODO: Move to reloadConfig() @@ -326,8 +333,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC GBAKeyEditor* buttonEditor = nullptr; #ifdef BUILD_SDL - inputController->recalibrateAxes(); - const char* profile = inputController->profileForType(SDL_BINDING_BUTTON); + QString profile = inputController->profileForType(SDL_BINDING_BUTTON); buttonEditor = new GBAKeyEditor(inputController, SDL_BINDING_BUTTON, profile); addPage(tr("Controllers"), buttonEditor, Page::CONTROLLERS); connect(m_ui.buttonBox, &QDialogButtonBox::accepted, buttonEditor, &GBAKeyEditor::save); @@ -347,7 +353,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC QLocale englishLocale("en"); m_ui.languages->addItem(englishLocale.nativeLanguageName(), englishLocale); QDir ts(":/translations/"); - for (auto name : ts.entryList()) { + for (auto& name : ts.entryList()) { if (!name.endsWith(".qm") || !name.startsWith(binaryName)) { continue; } @@ -442,6 +448,13 @@ void SettingsView::selectPath(QLineEdit* field, QCheckBox* sameDir) { } } +void SettingsView::selectImage(QLineEdit* field) { + QString path = GBAApp::app()->getOpenFileName(this, tr("Select image"), tr("Image file (*.png *.jpg *.jpeg)")); + if (!path.isNull()) { + field->setText(makePortablePath(path)); + } +} + void SettingsView::updateConfig() { saveSetting("gba.bios", m_ui.gbaBios); saveSetting("gb.bios", m_ui.gbBios); @@ -467,6 +480,7 @@ void SettingsView::updateConfig() { saveSetting("fastForwardMute", m_ui.muteFf); saveSetting("rewindEnable", m_ui.rewind); saveSetting("rewindBufferCapacity", m_ui.rewindCapacity); + saveSetting("rewindBufferInterval", m_ui.rewindBufferInterval); saveSetting("resampleVideo", m_ui.resampleVideo); saveSetting("allowOpposingDirections", m_ui.allowOpposingDirections); saveSetting("suspendScreensaver", m_ui.suspendScreensaver); @@ -498,6 +512,7 @@ void SettingsView::updateConfig() { saveSetting("vbaBugCompat", m_ui.vbaBugCompat); saveSetting("updateAutoCheck", m_ui.updateAutoCheck); saveSetting("showFilenameInLibrary", m_ui.showFilenameInLibrary); + saveSetting("backgroundImage", m_ui.bgImage); if (m_ui.audioBufferSize->currentText().toInt() > 8192) { m_ui.audioBufferSize->setCurrentText("8192"); @@ -694,11 +709,14 @@ void SettingsView::reloadConfig() { loadSetting("fastForwardMute", m_ui.muteFf, m_ui.mute->isChecked()); loadSetting("rewindEnable", m_ui.rewind); loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); + loadSetting("rewindBufferInterval", m_ui.rewindBufferInterval); loadSetting("resampleVideo", m_ui.resampleVideo); loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections); loadSetting("suspendScreensaver", m_ui.suspendScreensaver); loadSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost); loadSetting("pauseOnMinimize", m_ui.pauseOnMinimize); + loadSetting("muteOnFocusLost", m_ui.muteOnFocusLost); + loadSetting("muteOnMinimize", m_ui.muteOnMinimize); loadSetting("savegamePath", m_ui.savegamePath); loadSetting("savestatePath", m_ui.savestatePath); loadSetting("screenshotPath", m_ui.screenshotPath); @@ -722,6 +740,7 @@ void SettingsView::reloadConfig() { loadSetting("vbaBugCompat", m_ui.vbaBugCompat, true); loadSetting("updateAutoCheck", m_ui.updateAutoCheck); loadSetting("showFilenameInLibrary", m_ui.showFilenameInLibrary); + loadSetting("backgroundImage", m_ui.bgImage); m_ui.libraryStyle->setCurrentIndex(loadSetting("libraryStyle").toInt()); diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index d13a6b453..3543419fc 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -71,6 +71,7 @@ public slots: private slots: void selectBios(QLineEdit*); void selectPath(QLineEdit*, QCheckBox*); + void selectImage(QLineEdit*); void updateConfig(); void reloadConfig(); void updateChecked(); diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index f0869aca5..42e4af5a0 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -6,8 +6,8 @@ 0 0 - 885 - 797 + 880 + 700 @@ -95,7 +95,7 @@ - 9 + 0 @@ -907,6 +907,41 @@ + + + + + + + 0 + 0 + + + + + + + + Browse + + + + + + + + + Qt::Horizontal + + + + + + + Custom border: + + + @@ -1160,21 +1195,51 @@ - + + + + Rewind speed: + + + + + + + + + × + + + 1 + + + 10 + + + 1 + + + 1 + + + + + + Qt::Horizontal - + Idle loops: - + @@ -1193,21 +1258,21 @@ - + Preload entire ROM into memory - + Enable Game Boy Player features by default - + Enable VBA bug compatibility in ROM hacks @@ -1836,8 +1901,8 @@ - 30 - 30 + 24 + 24 @@ -1855,8 +1920,8 @@ - 30 - 30 + 24 + 24 @@ -1874,8 +1939,8 @@ - 30 - 30 + 24 + 24 @@ -1893,8 +1958,8 @@ - 30 - 30 + 24 + 24 @@ -1923,8 +1988,8 @@ - 30 - 30 + 24 + 24 @@ -1942,8 +2007,8 @@ - 30 - 30 + 24 + 24 @@ -1961,8 +2026,8 @@ - 30 - 30 + 24 + 24 @@ -1980,8 +2045,8 @@ - 30 - 30 + 24 + 24 @@ -2010,8 +2075,8 @@ - 30 - 30 + 24 + 24 @@ -2029,8 +2094,8 @@ - 30 - 30 + 24 + 24 @@ -2048,8 +2113,8 @@ - 30 - 30 + 24 + 24 @@ -2067,8 +2132,8 @@ - 30 - 30 + 24 + 24 @@ -2091,45 +2156,37 @@ - - - - Default color palette only - - - gbColors - - - - - - - SGB color palette if available - - - gbColors - - - - - - - GBC color palette if available - - - gbColors - - - - - - - SGB (preferred) or GBC color palette if available - - - gbColors - - + + + + + + SGB color palette if available + + + + + + + Default color palette only + + + + + + + GBC color palette if available + + + + + + + SGB (preferred) or GBC color palette if available + + + + diff --git a/src/platform/qt/ShaderSelector.cpp b/src/platform/qt/ShaderSelector.cpp index 80a8fcd9d..44bca3855 100644 --- a/src/platform/qt/ShaderSelector.cpp +++ b/src/platform/qt/ShaderSelector.cpp @@ -19,8 +19,8 @@ #include #include +#include #include -#include "platform/video-backend.h" #if defined(BUILD_GL) || defined(BUILD_GLES2) @@ -63,7 +63,11 @@ void ShaderSelector::clear() { void ShaderSelector::selectShader() { QDir path(GBAApp::dataDir()); path.cd(QLatin1String("shaders")); +#if !defined(USE_LIBZIP) && !defined(USE_MINIZIP) QString name = GBAApp::app()->getOpenDirectoryName(this, tr("Load shader"), path.absolutePath()); +#else + QString name = GBAApp::app()->getOpenFileName(this, tr("Load shader"), "mGBA Shaders (*.shader)", path.absolutePath()); +#endif if (!name.isNull()) { loadShader(name); refreshShaders(); diff --git a/src/platform/qt/ShortcutController.cpp b/src/platform/qt/ShortcutController.cpp index d401fd1ba..d1165a9ba 100644 --- a/src/platform/qt/ShortcutController.cpp +++ b/src/platform/qt/ShortcutController.cpp @@ -6,8 +6,10 @@ #include "ShortcutController.h" #include "ConfigController.h" -#include "GamepadButtonEvent.h" +#include "input/GamepadButtonEvent.h" +#include "input/GamepadHatEvent.h" #include "InputProfile.h" +#include "scripting/ScriptingController.h" #include #include @@ -32,6 +34,10 @@ void ShortcutController::setActionMapper(ActionMapper* actions) { rebuildItems(); } +void ShortcutController::setScriptingController(ScriptingController* controller) { + m_scripting = controller; +} + void ShortcutController::updateKey(const QString& name, int keySequence) { auto item = m_items[name]; if (!item) { @@ -132,9 +138,14 @@ void ShortcutController::rebuildItems() { onSubitems({}, std::bind(&ShortcutController::generateItem, this, std::placeholders::_1)); } -bool ShortcutController::eventFilter(QObject*, QEvent* event) { +bool ShortcutController::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { QKeyEvent* keyEvent = static_cast(event); +#ifdef ENABLE_SCRIPTING + if (m_scripting) { + m_scripting->event(obj, event); + } +#endif if (keyEvent->isAutoRepeat()) { return false; } @@ -149,15 +160,19 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) { Action::BooleanFunction fn = item.value()->action()->booleanAction(); fn(event->type() == QEvent::KeyPress); event->accept(); - return true; } } if (event->type() == GamepadButtonEvent::Down()) { +#ifdef ENABLE_SCRIPTING + if (m_scripting) { + m_scripting->event(obj, event); + } +#endif auto item = m_buttons.find(static_cast(event)->value()); if (item == m_buttons.end()) { return false; } - Action* action = item.value()->action(); + auto action = item.value()->action(); if (action) { if (m_actions->isHeld(action->name())) { action->trigger(true); @@ -169,11 +184,16 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) { return true; } if (event->type() == GamepadButtonEvent::Up()) { +#ifdef ENABLE_SCRIPTING + if (m_scripting) { + m_scripting->event(obj, event); + } +#endif auto item = m_buttons.find(static_cast(event)->value()); if (item == m_buttons.end()) { return false; } - Action* action = item.value()->action(); + auto action = item.value()->action(); if (action && m_actions->isHeld(action->name())) { action->trigger(false); } @@ -186,7 +206,7 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) { if (item == m_axes.end()) { return false; } - Action* action = item.value()->action(); + auto action = item.value()->action(); if (action) { if (gae->isNew()) { if (m_actions->isHeld(action->name())) { @@ -201,6 +221,13 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) { event->accept(); return true; } +#ifdef ENABLE_SCRIPTING + if (event->type() == GamepadHatEvent::Type()) { + if (m_scripting) { + m_scripting->event(obj, event); + } + } +#endif return false; } @@ -208,7 +235,7 @@ void ShortcutController::generateItem(const QString& itemName) { if (itemName.isNull() || itemName[0] == '.') { return; } - Action* action = m_actions->getAction(itemName); + auto action = m_actions->getAction(itemName); if (action) { std::shared_ptr item = std::make_shared(action); m_items[itemName] = item; @@ -299,7 +326,7 @@ void ShortcutController::loadProfile(const QString& profile) { m_profileName = profile; m_profile = InputProfile::findProfile(profile); onSubitems({}, [this](std::shared_ptr item) { - loadGamepadShortcuts(item); + loadGamepadShortcuts(std::move(item)); }); } @@ -435,7 +462,7 @@ int ShortcutController::count(const QString& name) const { return menu.count(); } -Shortcut::Shortcut(Action* action) +Shortcut::Shortcut(std::shared_ptr action) : m_action(action) { } diff --git a/src/platform/qt/ShortcutController.h b/src/platform/qt/ShortcutController.h index eb24cdc96..089032d34 100644 --- a/src/platform/qt/ShortcutController.h +++ b/src/platform/qt/ShortcutController.h @@ -6,7 +6,7 @@ #pragma once #include "ActionMapper.h" -#include "GamepadAxisEvent.h" +#include "input/GamepadAxisEvent.h" #include #include @@ -21,15 +21,16 @@ namespace QGBA { class ConfigController; class InputProfile; +class ScriptingController; class Shortcut : public QObject { Q_OBJECT public: - Shortcut(Action* action); + Shortcut(std::shared_ptr action); - Action* action() { return m_action; } - const Action* action() const { return m_action; } + std::shared_ptr action() { return m_action; } + const std::shared_ptr action() const { return m_action; } int shortcut() const { return m_shortcut; } QString visibleName() const { return m_action ? m_action->visibleName() : QString(); } QString name() const { return m_action ? m_action->name() : QString(); } @@ -52,11 +53,11 @@ signals: void axisChanged(int axis, GamepadAxisEvent::Direction direction); private: - Action* m_action = nullptr; + std::shared_ptr m_action; int m_shortcut = 0; int m_button = -1; int m_axis = -1; - GamepadAxisEvent::Direction m_direction; + GamepadAxisEvent::Direction m_direction = GamepadAxisEvent::NEUTRAL; }; class ShortcutController : public QObject { @@ -74,6 +75,7 @@ public: void setConfigController(ConfigController* controller); void setActionMapper(ActionMapper* actionMapper); + void setScriptingController(ScriptingController* scriptingController); void setProfile(const QString& profile); @@ -121,6 +123,7 @@ private: QHash> m_heldKeys; ActionMapper* m_actions = nullptr; ConfigController* m_config = nullptr; + ScriptingController* m_scripting = nullptr; QString m_profileName; const InputProfile* m_profile = nullptr; }; diff --git a/src/platform/qt/ShortcutModel.cpp b/src/platform/qt/ShortcutModel.cpp index 54fa83fcf..b73982cad 100644 --- a/src/platform/qt/ShortcutModel.cpp +++ b/src/platform/qt/ShortcutModel.cpp @@ -6,6 +6,7 @@ #include "ShortcutModel.h" #include "ShortcutController.h" +#include "utils.h" using namespace QGBA; @@ -33,7 +34,7 @@ QVariant ShortcutModel::data(const QModelIndex& index, int role) const { case 0: return m_controller->visibleName(item->name); case 1: - return shortcut ? QKeySequence(shortcut->shortcut()).toString(QKeySequence::NativeText) : QVariant(); + return shortcut ? keyName(shortcut->shortcut()) : QVariant(); case 2: if (!shortcut) { return QVariant(); @@ -134,4 +135,4 @@ void ShortcutModel::clearMenu(const QString&) { // TODO beginResetModel(); endResetModel(); -} \ No newline at end of file +} diff --git a/src/platform/qt/ShortcutView.cpp b/src/platform/qt/ShortcutView.cpp index e82c2dd9b..5efbc4d62 100644 --- a/src/platform/qt/ShortcutView.cpp +++ b/src/platform/qt/ShortcutView.cpp @@ -5,8 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ShortcutView.h" -#include "GamepadButtonEvent.h" #include "InputController.h" +#include "input/GamepadButtonEvent.h" #include "ShortcutController.h" #include "ShortcutModel.h" diff --git a/src/platform/qt/ShortcutView.h b/src/platform/qt/ShortcutView.h index 903d365c8..d2e307419 100644 --- a/src/platform/qt/ShortcutView.h +++ b/src/platform/qt/ShortcutView.h @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once -#include "GamepadAxisEvent.h" +#include "input/GamepadAxisEvent.h" #include diff --git a/src/platform/qt/TileView.cpp b/src/platform/qt/TileView.cpp index 116935e29..7d8d1a71e 100644 --- a/src/platform/qt/TileView.cpp +++ b/src/platform/qt/TileView.cpp @@ -51,7 +51,7 @@ TileView::TileView(std::shared_ptr controller, QWidget* parent) #ifdef M_CORE_GBA case mPLATFORM_GBA: m_ui.tile->setBoundary(2048, 0, 2); - m_ui.tile->setMaxTile(3096); + m_ui.tile->setMaxTile(3072); break; #endif #ifdef M_CORE_GB @@ -76,7 +76,7 @@ TileView::TileView(std::shared_ptr controller, QWidget* parent) #ifdef M_CORE_GBA case mPLATFORM_GBA: m_ui.tile->setBoundary(2048 >> selected, selected, selected + 2); - m_ui.tile->setMaxTile(3096 >> selected); + m_ui.tile->setMaxTile(3072 >> selected); break; #endif #ifdef M_CORE_GB diff --git a/src/platform/qt/VideoProxy.cpp b/src/platform/qt/VideoProxy.cpp index 7c6366229..2b24e7121 100644 --- a/src/platform/qt/VideoProxy.cpp +++ b/src/platform/qt/VideoProxy.cpp @@ -12,68 +12,93 @@ using namespace QGBA; VideoProxy::VideoProxy() { - mVideoLoggerRendererCreate(&m_logger.d, false); - m_logger.d.block = true; - m_logger.d.waitOnFlush = true; + mVideoLoggerRendererCreate(&m_logger, false); + m_logger.p = this; + m_logger.block = true; + m_logger.waitOnFlush = true; - m_logger.d.init = &cbind<&VideoProxy::init>; - m_logger.d.reset = &cbind<&VideoProxy::reset>; - m_logger.d.deinit = &cbind<&VideoProxy::deinit>; - m_logger.d.lock = &cbind<&VideoProxy::lock>; - m_logger.d.unlock = &cbind<&VideoProxy::unlock>; - m_logger.d.wait = &cbind<&VideoProxy::wait>; - m_logger.d.wake = &callback::func<&VideoProxy::wake>; + m_logger.init = &cbind<&VideoProxy::init>; + m_logger.reset = &cbind<&VideoProxy::reset>; + m_logger.deinit = &cbind<&VideoProxy::deinit>; + m_logger.lock = &cbind<&VideoProxy::lock>; + m_logger.unlock = &cbind<&VideoProxy::unlock>; + m_logger.wait = &cbind<&VideoProxy::wait>; + m_logger.wake = &callback::func<&VideoProxy::wake>; + RingFIFOInit(&m_dirtyQueue, 0x80000); - m_logger.d.writeData = &callback::func<&VideoProxy::writeData>; - m_logger.d.readData = &callback::func<&VideoProxy::readData>; - m_logger.d.postEvent = &callback::func<&VideoProxy::postEvent>; + m_logger.writeData = &callback::func<&VideoProxy::writeData>; + m_logger.readData = &callback::func<&VideoProxy::readData>; + m_logger.postEvent = &callback::func<&VideoProxy::postEvent>; + + mVideoProxyBackendInit(&m_backend, nullptr); + m_backend.context = this; + m_backend.wakeupCb = [](struct mVideoProxyBackend*, void* context) { + VideoProxy* self = static_cast(context); + QMetaObject::invokeMethod(self, "commandAvailable"); + }; connect(this, &VideoProxy::dataAvailable, this, &VideoProxy::processData); + connect(this, &VideoProxy::commandAvailable, this, &VideoProxy::processCommands); +} + +VideoProxy::~VideoProxy() { + mVideoProxyBackendDeinit(&m_backend); + RingFIFODeinit(&m_dirtyQueue); } void VideoProxy::attach(CoreController* controller) { CoreController::Interrupter interrupter(controller); - controller->thread()->core->videoLogger = &m_logger.d; + m_logContext = &controller->thread()->logger.d; + controller->thread()->core->videoLogger = &m_logger; } void VideoProxy::detach(CoreController* controller) { CoreController::Interrupter interrupter(controller); - if (controller->thread()->core->videoLogger == &m_logger.d) { + if (controller->thread()->core->videoLogger == &m_logger) { + m_logContext = nullptr; controller->thread()->core->videoLogger = nullptr; } } +void VideoProxy::setProxiedBackend(VideoBackend* backend) { + // TODO: This needs some safety around it + m_backend.backend = backend; +} + void VideoProxy::processData() { - mVideoLoggerRendererRun(&m_logger.d, false); + mLogSetThreadLogger(m_logContext); + mVideoLoggerRendererRun(&m_logger, false); m_fromThreadCond.wakeAll(); } +void VideoProxy::processCommands() { + mLogSetThreadLogger(m_logContext); + mVideoProxyBackendRun(&m_backend, false); +} + void VideoProxy::init() { - RingFIFOInit(&m_dirtyQueue, 0x80000); } void VideoProxy::reset() { - m_mutex.lock(); + QMutexLocker locker(&m_mutex); RingFIFOClear(&m_dirtyQueue); m_toThreadCond.wakeAll(); - m_mutex.unlock(); } void VideoProxy::deinit() { - RingFIFODeinit(&m_dirtyQueue); } bool VideoProxy::writeData(const void* data, size_t length) { while (!RingFIFOWrite(&m_dirtyQueue, data, length)) { if (QThread::currentThread() == thread()) { // We're on the main thread - mVideoLoggerRendererRun(&m_logger.d, false); + mLogSetThreadLogger(m_logContext); + mVideoLoggerRendererRun(&m_logger, false); } else { emit dataAvailable(); - m_mutex.lock(); + QMutexLocker locker(&m_mutex); m_toThreadCond.wakeAll(); m_fromThreadCond.wait(&m_mutex); - m_mutex.unlock(); } } return true; @@ -86,10 +111,9 @@ bool VideoProxy::readData(void* data, size_t length, bool block) { if (!block || read) { break; } - m_mutex.lock(); + QMutexLocker locker(&m_mutex); m_fromThreadCond.wakeAll(); m_toThreadCond.wait(&m_mutex); - m_mutex.unlock(); } return read; } @@ -104,9 +128,9 @@ void VideoProxy::postEvent(enum mVideoLoggerEvent event) { } void VideoProxy::handleEvent(int event) { - m_mutex.lock(); - m_logger.d.handleEvent(&m_logger.d, static_cast(event)); - m_mutex.unlock(); + QMutexLocker locker(&m_mutex); + mLogSetThreadLogger(m_logContext); + m_logger.handleEvent(&m_logger, static_cast(event)); } void VideoProxy::lock() { @@ -118,18 +142,18 @@ void VideoProxy::unlock() { } void VideoProxy::wait() { - m_mutex.lock(); + QMutexLocker locker(&m_mutex); while (RingFIFOSize(&m_dirtyQueue)) { if (QThread::currentThread() == thread()) { // We're on the main thread - mVideoLoggerRendererRun(&m_logger.d, false); + mLogSetThreadLogger(m_logContext); + mVideoLoggerRendererRun(&m_logger, false); } else { emit dataAvailable(); m_toThreadCond.wakeAll(); m_fromThreadCond.wait(&m_mutex, 1); } } - m_mutex.unlock(); } void VideoProxy::wake(int y) { diff --git a/src/platform/qt/VideoProxy.h b/src/platform/qt/VideoProxy.h index 3ba845617..8cb1020cd 100644 --- a/src/platform/qt/VideoProxy.h +++ b/src/platform/qt/VideoProxy.h @@ -7,9 +7,13 @@ #include #include +#include +#include #include +#include #include +#include #include namespace QGBA { @@ -21,16 +25,22 @@ Q_OBJECT public: VideoProxy(); + ~VideoProxy(); void attach(CoreController*); void detach(CoreController*); - void setBlocking(bool block) { m_logger.d.waitOnFlush = block; } + void setBlocking(bool block) { m_logger.waitOnFlush = block; } + + VideoBackend* backend() { return &m_backend.d; } + void setProxiedBackend(VideoBackend*); signals: void dataAvailable(); + void commandAvailable(); public slots: void processData(); + void processCommands(); void reset(); void handleEvent(int); @@ -51,22 +61,31 @@ private: using type = T (VideoProxy::*)(A...); template static T func(mVideoLogger* logger, A... args) { - VideoProxy* proxy = reinterpret_cast(logger)->p; + VideoProxy* proxy = static_cast(logger)->p; return (proxy->*F)(args...); } }; template static void cbind(mVideoLogger* logger) { callback::func(logger); } - struct Logger { - mVideoLogger d; + struct Logger : public mVideoLogger { VideoProxy* p; - } m_logger = {{}, this}; + } m_logger; + + struct mVideoProxyBackend m_backend; + struct mLogger* m_logContext = nullptr; RingFIFO m_dirtyQueue; QMutex m_mutex; QWaitCondition m_toThreadCond; QWaitCondition m_fromThreadCond; + + QReadWriteLock m_backendInLock; + QReadWriteLock m_backendOutLock; + QQueue m_backendIn; + QQueue m_backendOut; + QWaitCondition m_toBackendThreadCond; + QWaitCondition m_fromBackendThreadCond; }; } diff --git a/src/platform/qt/VideoView.cpp b/src/platform/qt/VideoView.cpp index 3b6382275..b03949c2f 100644 --- a/src/platform/qt/VideoView.cpp +++ b/src/platform/qt/VideoView.cpp @@ -20,6 +20,7 @@ using namespace QGBA; QMap VideoView::s_acodecMap; QMap VideoView::s_vcodecMap; QMap VideoView::s_containerMap; +QMap VideoView::s_extensionMap; bool VideoView::Preset::compatible(const Preset& other) const { if (!other.container.isNull() && !container.isNull() && other.container != container) { @@ -71,6 +72,23 @@ VideoView::VideoView(QWidget* parent) if (s_containerMap.empty()) { s_containerMap["mkv"] = "matroska"; } + if (s_extensionMap.empty()) { + s_extensionMap["matroska"] += ".mkv"; + s_extensionMap["matroska"] += ".mka"; + s_extensionMap["webm"] += ".webm"; + s_extensionMap["avi"] += ".avi"; + s_extensionMap["mp4"] += ".mp4"; + s_extensionMap["mp4"] += ".m4v"; + s_extensionMap["mp4"] += ".m4a"; + + s_extensionMap["flac"] += ".flac"; + s_extensionMap["mpeg"] += ".mpg"; + s_extensionMap["mpeg"] += ".mpeg"; + s_extensionMap["mpegts"] += ".ts"; + s_extensionMap["mp3"] += ".mp3"; + s_extensionMap["ogg"] += ".ogg"; + s_extensionMap["ogv"] += ".ogv"; + } connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &VideoView::close); connect(m_ui.start, &QAbstractButton::clicked, this, &VideoView::startRecording); @@ -195,6 +213,9 @@ void VideoView::setController(std::shared_ptr controller) { } void VideoView::startRecording() { + if (QFileInfo(m_filename).suffix().isEmpty()) { + changeExtension(); + } if (!validateSettings()) { return; } @@ -238,6 +259,7 @@ void VideoView::selectFile() { QString filename = GBAApp::app()->getSaveFileName(this, tr("Select output file")); if (!filename.isEmpty()) { m_ui.filename->setText(filename); + changeExtension(); } } @@ -289,6 +311,7 @@ void VideoView::setContainer(const QString& container) { m_containerCstr = nullptr; m_container = QString(); } + changeExtension(); validateSettings(); uncheckIncompatible(); } @@ -458,6 +481,30 @@ void VideoView::uncheckIncompatible() { } } +void VideoView::changeExtension() { + if (m_filename.isEmpty()) { + return; + } + + if (!s_extensionMap.contains(m_container)) { + return; + } + + QStringList extensions = s_extensionMap.value(m_container); + QString filename = m_filename; + int index = m_filename.lastIndexOf("."); + if (index >= 0) { + if (extensions.contains(filename.mid(index))) { + // This extension is already valid + return; + } + filename.truncate(index); + } + filename += extensions.front(); + + m_ui.filename->setText(filename); +} + QString VideoView::sanitizeCodec(const QString& codec, const QMap& mapping) { QString sanitized = codec.toLower(); sanitized = sanitized.remove(QChar('.')); diff --git a/src/platform/qt/VideoView.h b/src/platform/qt/VideoView.h index 7c2bd99e0..9e3ab5ca2 100644 --- a/src/platform/qt/VideoView.h +++ b/src/platform/qt/VideoView.h @@ -7,6 +7,7 @@ #ifdef USE_FFMPEG +#include #include #include @@ -62,6 +63,8 @@ private slots: void uncheckIncompatible(); void updatePresets(); + void changeExtension(); + private: struct Preset { QString container; @@ -72,7 +75,7 @@ private: QSize dims; Preset() {} - Preset(QString container, QString vcodec, QString acodec, int vbr, int abr, QSize dims = QSize()) + Preset(const QString& container, const QString& vcodec, const QString& acodec, int vbr, int abr, QSize dims = QSize()) : container(container) , vcodec(vcodec) , acodec(acodec) @@ -123,6 +126,7 @@ private: static QMap s_acodecMap; static QMap s_vcodecMap; static QMap s_containerMap; + static QMap s_extensionMap; }; } diff --git a/src/platform/qt/VideoView.ui b/src/platform/qt/VideoView.ui index 53523653f..c56c5e1b5 100644 --- a/src/platform/qt/VideoView.ui +++ b/src/platform/qt/VideoView.ui @@ -247,22 +247,22 @@ - MKV + MKV - WebM + WebM - AVI + AVI - MP4 + MP4 @@ -274,42 +274,42 @@ - H.264 + H.264 - H.264 (NVENC) + H.264 (NVENC) - HEVC + HEVC - HEVC (NVENC) + HEVC (NVENC) - VP8 + VP8 - VP9 + VP9 - FFV1 + FFV1 - None + None @@ -321,42 +321,42 @@ - FLAC + FLAC - WavPack + WavPack - Opus + Opus - Vorbis + Vorbis - MP3 + MP3 - AAC + AAC - Uncompressed + Uncompressed - None + None diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index cdfb5b9c1..6b77a1ef3 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -36,10 +36,14 @@ #include "GDBController.h" #include "GDBWindow.h" #include "GIFView.h" +#ifdef BUILD_SDL +#include "input/SDLInputDriver.h" +#endif #include "IOViewer.h" #include "LoadSaveState.h" #include "LogView.h" #include "MapView.h" +#include "MemoryAccessLogView.h" #include "MemorySearch.h" #include "MemoryView.h" #include "MultiplayerController.h" @@ -76,6 +80,7 @@ #include #endif #include +#include #include #include @@ -88,7 +93,7 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi , m_logView(new LogView(&m_log, this)) , m_screenWidget(new WindowBackground()) , m_config(config) - , m_inputController(playerId, this) + , m_inputController(this) , m_shortcutController(new ShortcutController(this)) , m_playerId(playerId) { @@ -170,6 +175,12 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi m_mustReset.setInterval(MUST_RESTART_TIMEOUT); m_mustReset.setSingleShot(true); +#ifdef BUILD_SDL + m_inputController.addInputDriver(std::make_shared(&m_inputController)); + m_inputController.setGamepadDriver(SDL_BINDING_BUTTON); + m_inputController.setSensorDriver(SDL_BINDING_BUTTON); +#endif + m_shortcutController->setConfigController(m_config); m_shortcutController->setActionMapper(&m_actions); setupMenu(menuBar()); @@ -196,15 +207,21 @@ void Window::argumentsPassed() { } #ifdef USE_GDB_STUB - if (args->debuggerType == DEBUGGER_GDB) { + if (args->debugGdb) { if (!m_gdbController) { m_gdbController = new GDBController(this); - if (m_controller) { - m_gdbController->setController(m_controller); - } - m_gdbController->attach(); - m_gdbController->listen(); } + if (m_controller) { + m_gdbController->setController(m_controller); + } + m_gdbController->attach(); + m_gdbController->listen(); + } +#endif + +#ifdef USE_DEBUGGERS + if (args->debugCli) { + consoleOpen(); } #endif @@ -248,12 +265,7 @@ void Window::resizeFrame(const QSize& size) { void Window::updateMultiplayerStatus(bool canOpenAnother) { m_multiWindow->setEnabled(canOpenAnother); - if (m_controller) { - MultiplayerController* multiplayer = m_controller->multiplayerController(); - if (multiplayer) { - m_playerId = multiplayer->playerId(m_controller.get()); - } - } + multiplayerChanged(); } void Window::updateMultiplayerActive(bool active) { @@ -297,7 +309,7 @@ void Window::reloadConfig() { m_display->resizeContext(); } - m_inputController.setScreensaverSuspendable(opts->suspendScreensaver); + GBAApp::app()->setScreensaverSuspendable(opts->suspendScreensaver); } void Window::saveConfig() { @@ -403,8 +415,9 @@ void Window::multiplayerChanged() { MultiplayerController* multiplayer = m_controller->multiplayerController(); if (multiplayer) { attached = multiplayer->attached(); + m_playerId = multiplayer->playerId(m_controller.get()); } - for (Action* action : m_nonMpActions) { + for (auto& action : m_nonMpActions) { action->setEnabled(attached < 2); } } @@ -557,6 +570,7 @@ template std::function Window::openControllerTView(A... arg) { return [=]() { T* view = new T(m_controller, arg...); + connect(m_controller.get(), &CoreController::stopping, view, &QWidget::close); openView(view); }; } @@ -617,9 +631,14 @@ void Window::consoleOpen() { void Window::scriptingOpen() { if (!m_scripting) { m_scripting = std::make_unique(); + m_scripting->setInputController(&m_inputController); + m_shortcutController->setScriptingController(m_scripting.get()); if (m_controller) { m_scripting->setController(m_controller); + m_display->installEventFilter(m_scripting.get()); } + + m_scripting->setVideoBackend(m_display->videoBackend()); } ScriptingView* view = new ScriptingView(m_scripting.get(), m_config); openView(view); @@ -631,8 +650,8 @@ void Window::keyPressEvent(QKeyEvent* event) { QWidget::keyPressEvent(event); return; } - GBAKey key = m_inputController.mapKeyboard(event->key()); - if (key == GBA_KEY_NONE) { + int key = m_inputController.mapKeyboard(event->key()); + if (key == -1) { QWidget::keyPressEvent(event); return; } @@ -647,8 +666,8 @@ void Window::keyReleaseEvent(QKeyEvent* event) { QWidget::keyReleaseEvent(event); return; } - GBAKey key = m_inputController.mapKeyboard(event->key()); - if (key == GBA_KEY_NONE) { + int key = m_inputController.mapKeyboard(event->key()); + if (key == -1) { QWidget::keyPressEvent(event); return; } @@ -675,7 +694,7 @@ void Window::resizeEvent(QResizeEvent*) { factor = newSize.width() / size.width(); } m_savedScale = factor; - for (QMap::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) { + for (QMap>::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) { iter.value()->setActive(iter.key() == factor); } @@ -797,13 +816,6 @@ void Window::dropEvent(QDropEvent* event) { setController(m_manager->loadGame(url.toLocalFile()), url.toLocalFile()); } -void Window::mouseDoubleClickEvent(QMouseEvent* event) { - if (event->button() != Qt::LeftButton) { - return; - } - toggleFullScreen(); -} - void Window::enterFullScreen() { if (!isVisible()) { m_fullscreenOnStart = true; @@ -838,7 +850,7 @@ void Window::toggleFullScreen() { } void Window::gameStarted() { - for (Action* action : m_gameActions) { + for (auto& action : m_gameActions) { action->setEnabled(true); } for (auto action = m_platformActions.begin(); action != m_platformActions.end(); ++action) { @@ -886,7 +898,7 @@ void Window::gameStarted() { if (nVideo) { for (size_t i = 0; i < nVideo; ++i) { - Action* action = m_actions.addBooleanAction(videoLayers[i].visibleName, QString("videoLayer.%1").arg(videoLayers[i].internalName), [this, videoLayers, i](bool enable) { + auto action = m_actions.addBooleanAction(videoLayers[i].visibleName, QString("videoLayer.%1").arg(videoLayers[i].internalName), [this, videoLayers, i](bool enable) { m_controller->thread()->core->enableVideoLayer(m_controller->thread()->core, videoLayers[i].id, enable); }, "videoLayers"); action->setActive(true); @@ -894,7 +906,7 @@ void Window::gameStarted() { } if (nAudio) { for (size_t i = 0; i < nAudio; ++i) { - Action* action = m_actions.addBooleanAction(audioChannels[i].visibleName, QString("audioChannel.%1").arg(audioChannels[i].internalName), [this, audioChannels, i](bool enable) { + auto action = m_actions.addBooleanAction(audioChannels[i].visibleName, QString("audioChannel.%1").arg(audioChannels[i].internalName), [this, audioChannels, i](bool enable) { m_controller->thread()->core->enableAudioChannel(m_controller->thread()->core, audioChannels[i].id, enable); }, "audioChannels"); action->setActive(true); @@ -919,10 +931,10 @@ void Window::gameStarted() { } void Window::gameStopped() { - for (Action* action : m_platformActions) { + for (auto& action : m_platformActions) { action->setEnabled(true); } - for (Action* action : m_gameActions) { + for (auto& action : m_gameActions) { action->setEnabled(false); } setWindowFilePath(QString()); @@ -952,6 +964,12 @@ void Window::gameStopped() { updateTitle(); if (m_pendingClose) { +#ifdef ENABLE_SCRIPTING + std::shared_ptr proxy = m_display->videoProxy(); + if (m_scripting && proxy) { + m_scripting->setVideoBackend(nullptr); + } +#endif m_display.reset(); close(); } @@ -1002,6 +1020,15 @@ void Window::reloadDisplayDriver() { m_display->stopDrawing(); detachWidget(); } +#ifdef ENABLE_SCRIPTING + if (m_scripting) { + m_scripting->setVideoBackend(nullptr); + } +#endif + std::shared_ptr proxy; + if (m_display) { + proxy = m_display->videoProxy(); + } m_display = std::unique_ptr(Display::create(this)); if (!m_display) { LOG(QT, ERROR) << tr("Failed to create an appropriate display device, falling back to software display. " @@ -1040,6 +1067,18 @@ void Window::reloadDisplayDriver() { #elif defined(M_CORE_GBA) m_display->setMinimumSize(GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); #endif + + m_display->setBackgroundImage(QImage{m_config->getOption("backgroundImage")}); + + if (!proxy) { + proxy = std::make_shared(); + } + m_display->setVideoProxy(proxy); +#ifdef ENABLE_SCRIPTING + if (m_scripting) { + m_scripting->setVideoBackend(m_display->videoBackend()); + } +#endif } void Window::reloadAudioDriver() { @@ -1064,12 +1103,7 @@ void Window::changeRenderer() { CoreController::Interrupter interrupter(m_controller); if (m_config->getOption("hwaccelVideo").toInt() && m_display->supportsShaders() && m_controller->supportsFeature(CoreController::Feature::OPENGL)) { - std::shared_ptr proxy = m_display->videoProxy(); - if (!proxy) { - proxy = std::make_shared(); - } - m_display->setVideoProxy(proxy); - proxy->attach(m_controller.get()); + m_display->videoProxy()->attach(m_controller.get()); int fb = m_display->framebufferHandle(); if (fb >= 0) { @@ -1077,11 +1111,7 @@ void Window::changeRenderer() { m_config->updateOption("videoScale"); } } else { - std::shared_ptr proxy = m_display->videoProxy(); - if (proxy) { - proxy->detach(m_controller.get()); - m_display->setVideoProxy({}); - } + m_display->videoProxy()->detach(m_controller.get()); m_controller->setFramebufferHandle(-1); } } @@ -1125,14 +1155,14 @@ void Window::recordFrame() { } void Window::showFPS() { - if (m_frameList.isEmpty()) { - updateTitle(); - return; - } qint64 total = 0; for (qint64 t : m_frameList) { total += t; } + if (!total) { + updateTitle(); + return; + } double fps = (m_frameList.size() * 1e10) / total; m_frameList.clear(); fps = round(fps) / 10.f; @@ -1153,11 +1183,11 @@ void Window::updateTitle(float fps) { MultiplayerController* multiplayer = m_controller->multiplayerController(); if (multiplayer && multiplayer->attached() > 1) { title += tr(" - Player %1 of %2").arg(m_playerId + 1).arg(multiplayer->attached()); - for (Action* action : m_nonMpActions) { + for (auto& action : m_nonMpActions) { action->setEnabled(false); } } else { - for (Action* action : m_nonMpActions) { + for (auto& action : m_nonMpActions) { action->setEnabled(true); } } @@ -1250,18 +1280,18 @@ void Window::setupMenu(QMenuBar* menubar) { m_actions.addSeparator("saves"); - m_actions.addAction(tr("Convert save game..."), "convertSave", openControllerTView(), "saves"); + m_actions.addAction(tr("Convert save game..."), "convertSave", openTView(), "saves"); #ifdef M_CORE_GBA - Action* importShark = addGameAction(tr("Import GameShark Save..."), "importShark", this, &Window::importSharkport, "saves"); + auto importShark = addGameAction(tr("Import GameShark Save..."), "importShark", this, &Window::importSharkport, "saves"); m_platformActions.insert(mPLATFORM_GBA, importShark); - Action* exportShark = addGameAction(tr("Export GameShark Save..."), "exportShark", this, &Window::exportSharkport, "saves"); + auto exportShark = addGameAction(tr("Export GameShark Save..."), "exportShark", this, &Window::exportSharkport, "saves"); m_platformActions.insert(mPLATFORM_GBA, exportShark); #endif m_actions.addSeparator("saves"); - Action* savePlayerAction; + std::shared_ptr savePlayerAction; ConfigOption* savePlayer = m_config->addOption("savePlayerId"); savePlayerAction = savePlayer->addValue(tr("Automatically determine"), 0, &m_actions, "saves"); m_nonMpActions.append(savePlayerAction); @@ -1284,7 +1314,7 @@ void Window::setupMenu(QMenuBar* menubar) { #endif #ifdef M_CORE_GBA - Action* scanCard = addGameAction(tr("Scan e-Reader dotcodes..."), "scanCard", this, &Window::scanCard, "file"); + auto scanCard = addGameAction(tr("Scan e-Reader dotcodes..."), "scanCard", this, &Window::scanCard, "file"); m_platformActions.insert(mPLATFORM_GBA, scanCard); #endif @@ -1293,22 +1323,22 @@ void Window::setupMenu(QMenuBar* menubar) { m_actions.addMenu(tr("Recent"), "mru", "file"); m_actions.addSeparator("file"); - Action* loadState = addGameAction(tr("&Load state"), "loadState", [this]() { + auto loadState = addGameAction(tr("&Load state"), "loadState", [this]() { this->openStateWindow(LoadSave::LOAD); }, "file", QKeySequence("F10")); m_nonMpActions.append(loadState); - Action* loadStateFile = addGameAction(tr("Load state file..."), "loadStateFile", [this]() { + auto loadStateFile = addGameAction(tr("Load state file..."), "loadStateFile", [this]() { this->selectState(true); }, "file"); m_nonMpActions.append(loadStateFile); - Action* saveState = addGameAction(tr("&Save state"), "saveState", [this]() { + auto saveState = addGameAction(tr("&Save state"), "saveState", [this]() { this->openStateWindow(LoadSave::SAVE); }, "file", QKeySequence("Shift+F10")); m_nonMpActions.append(saveState); - Action* saveStateFile = addGameAction(tr("Save state file..."), "saveStateFile", [this]() { + auto saveStateFile = addGameAction(tr("Save state file..."), "saveStateFile", [this]() { this->selectState(false); }, "file"); m_nonMpActions.append(saveStateFile); @@ -1316,12 +1346,12 @@ void Window::setupMenu(QMenuBar* menubar) { m_actions.addMenu(tr("Quick load"), "quickLoad", "file"); m_actions.addMenu(tr("Quick save"), "quickSave", "file"); - Action* quickLoad = addGameAction(tr("Load recent"), "quickLoad", [this] { + auto quickLoad = addGameAction(tr("Load recent"), "quickLoad", [this] { m_controller->loadState(); }, "quickLoad"); m_nonMpActions.append(quickLoad); - Action* quickSave = addGameAction(tr("Save recent"), "quickSave", [this] { + auto quickSave = addGameAction(tr("Save recent"), "quickSave", [this] { m_controller->saveState(); }, "quickSave"); m_nonMpActions.append(quickSave); @@ -1329,22 +1359,22 @@ void Window::setupMenu(QMenuBar* menubar) { m_actions.addSeparator("quickLoad"); m_actions.addSeparator("quickSave"); - Action* undoLoadState = addGameAction(tr("Undo load state"), "undoLoadState", &CoreController::loadBackupState, "quickLoad", QKeySequence("F11")); + auto undoLoadState = addGameAction(tr("Undo load state"), "undoLoadState", &CoreController::loadBackupState, "quickLoad", QKeySequence("F11")); m_nonMpActions.append(undoLoadState); - Action* undoSaveState = addGameAction(tr("Undo save state"), "undoSaveState", &CoreController::saveBackupState, "quickSave", QKeySequence("Shift+F11")); + auto undoSaveState = addGameAction(tr("Undo save state"), "undoSaveState", &CoreController::saveBackupState, "quickSave", QKeySequence("Shift+F11")); m_nonMpActions.append(undoSaveState); m_actions.addSeparator("quickLoad"); m_actions.addSeparator("quickSave"); for (int i = 1; i < 10; ++i) { - Action* quickLoad = addGameAction(tr("State &%1").arg(i), QString("quickLoad.%1").arg(i), [this, i]() { + auto quickLoad = addGameAction(tr("State &%1").arg(i), QString("quickLoad.%1").arg(i), [this, i]() { m_controller->loadState(i); }, "quickLoad", QString("F%1").arg(i)); m_nonMpActions.append(quickLoad); - Action* quickSave = addGameAction(tr("State &%1").arg(i), QString("quickSave.%1").arg(i), [this, i]() { + auto quickSave = addGameAction(tr("State &%1").arg(i), QString("quickSave.%1").arg(i), [this, i]() { m_controller->saveState(i); }, "quickSave", QString("Shift+F%1").arg(i)); m_nonMpActions.append(quickSave); @@ -1354,7 +1384,7 @@ void Window::setupMenu(QMenuBar* menubar) { m_multiWindow = m_actions.addAction(tr("New multiplayer window"), "multiWindow", GBAApp::app(), &GBAApp::newWindow, "file"); #ifdef M_CORE_GBA - Action* dolphin = m_actions.addAction(tr("Connect to Dolphin..."), "connectDolphin", openNamedTView(&m_dolphinView, this), "file"); + auto dolphin = m_actions.addAction(tr("Connect to Dolphin..."), "connectDolphin", openNamedTView(&m_dolphinView, this), "file"); m_platformActions.insert(mPLATFORM_GBA, dolphin); #endif @@ -1378,14 +1408,14 @@ void Window::setupMenu(QMenuBar* menubar) { addGameAction(tr("Yank game pak"), "yank", &CoreController::yankPak, "emu"); m_actions.addSeparator("emu"); - Action* pause = m_actions.addBooleanAction(tr("&Pause"), "pause", [this](bool paused) { + auto pause = m_actions.addBooleanAction(tr("&Pause"), "pause", [this](bool paused) { if (m_controller) { m_controller->setPaused(paused); } else { m_pendingPause = paused; } }, "emu", QKeySequence("Ctrl+P")); - connect(this, &Window::paused, pause, &Action::setActive); + connect(this, &Window::paused, pause.get(), &Action::setActive); addGameAction(tr("&Next frame"), "frameAdvance", &CoreController::frameAdvance, "emu", QKeySequence("Ctrl+N")); @@ -1414,19 +1444,33 @@ void Window::setupMenu(QMenuBar* menubar) { } m_config->updateOption("fastForwardRatio"); - Action* rewindHeld = m_actions.addHeldAction(tr("Rewind (held)"), "holdRewind", [this](bool held) { + addGameAction(tr("Increase fast forward speed"), "fastForwardUp", [this] { + float newRatio = m_config->getOption("fastForwardRatio", 1.0f).toFloat() + 1.0f; + if (newRatio >= 3.0f) { + m_config->setOption("fastForwardRatio", QVariant(newRatio)); + } + }, "emu"); + + addGameAction(tr("Decrease fast forward speed"), "fastForwardDown", [this] { + float newRatio = m_config->getOption("fastForwardRatio").toFloat() - 1.0f; + if (newRatio >= 2.0f) { + m_config->setOption("fastForwardRatio", QVariant(newRatio)); + } + }, "emu"); + + auto rewindHeld = m_actions.addHeldAction(tr("Rewind (held)"), "holdRewind", [this](bool held) { if (m_controller) { m_controller->setRewinding(held); } }, "emu", QKeySequence("`")); m_nonMpActions.append(rewindHeld); - Action* rewind = addGameAction(tr("Re&wind"), "rewind", [this]() { + auto rewind = addGameAction(tr("Re&wind"), "rewind", [this]() { m_controller->rewind(); }, "emu", QKeySequence("~")); m_nonMpActions.append(rewind); - Action* frameRewind = addGameAction(tr("Step backwards"), "frameRewind", [this] () { + auto frameRewind = addGameAction(tr("Step backwards"), "frameRewind", [this] () { m_controller->rewind(1); }, "emu", QKeySequence("Ctrl+B")); m_nonMpActions.append(frameRewind); @@ -1453,7 +1497,7 @@ void Window::setupMenu(QMenuBar* menubar) { #ifdef M_CORE_GB m_actions.addAction(tr("Load camera image..."), "loadCamImage", this, &Window::loadCamImage, "emu"); - Action* gbPrint = addGameAction(tr("Game Boy Printer..."), "gbPrint", [this]() { + auto gbPrint = addGameAction(tr("Game Boy Printer..."), "gbPrint", [this]() { PrinterView* view = new PrinterView(m_controller); openView(view); m_controller->attachPrinter(); @@ -1462,19 +1506,19 @@ void Window::setupMenu(QMenuBar* menubar) { #endif #ifdef M_CORE_GBA - Action* bcGate = addGameAction(tr("BattleChip Gate..."), "bcGate", openControllerTView(this), "emu"); + auto bcGate = addGameAction(tr("BattleChip Gate..."), "bcGate", openControllerTView(this), "emu"); m_platformActions.insert(mPLATFORM_GBA, bcGate); #endif m_actions.addMenu(tr("Audio/&Video"), "av"); m_actions.addMenu(tr("Frame size"), "frame", "av"); for (int i = 1; i <= 8; ++i) { - Action* setSize = m_actions.addAction(tr("%1×").arg(QString::number(i)), QString("frame.%1x").arg(QString::number(i)), [this, i]() { - Action* setSize = m_frameSizes[i]; + auto setSize = m_actions.addAction(tr("%1×").arg(QString::number(i)), QString("frame.%1x").arg(QString::number(i)), [this, i]() { + auto setSize = m_frameSizes[i]; showNormal(); QSize size(GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS); - if (m_controller) { - size = m_controller->screenDimensions(); + if (m_display) { + size = m_display->contentSize(); } size *= i; m_savedScale = i; @@ -1551,7 +1595,8 @@ void Window::setupMenu(QMenuBar* menubar) { m_actions.addSeparator("av"); ConfigOption* mute = m_config->addOption("mute"); - mute->addBoolean(tr("Mute"), &m_actions, "av"); + auto muteAction = mute->addBoolean(tr("Mute"), &m_actions, "av"); + muteAction->setActive(m_config->getOption("mute").toInt()); mute->connect([this](const QVariant& value) { m_config->setOption("fastForwardMute", static_cast(value.toInt())); reloadConfig(); @@ -1559,7 +1604,7 @@ void Window::setupMenu(QMenuBar* menubar) { m_actions.addMenu(tr("FPS target"),"target", "av"); ConfigOption* fpsTargetOption = m_config->addOption("fpsTarget"); - QMap fpsTargets; + QMap> fpsTargets; for (int fps : {15, 30, 45, 60, 90, 120, 240}) { fpsTargets[fps] = fpsTargetOption->addValue(QString::number(fps), fps, &m_actions, "target"); } @@ -1567,7 +1612,7 @@ void Window::setupMenu(QMenuBar* menubar) { double nativeGB = double(GBA_ARM7TDMI_FREQUENCY) / double(VIDEO_TOTAL_LENGTH); fpsTargets[nativeGB] = fpsTargetOption->addValue(tr("Native (59.7275)"), nativeGB, &m_actions, "target"); - fpsTargetOption->connect([this, fpsTargets](const QVariant& value) { + fpsTargetOption->connect([this, fpsTargets = std::move(fpsTargets)](const QVariant& value) { reloadConfig(); for (auto iter = fpsTargets.begin(); iter != fpsTargets.end(); ++iter) { bool enableSignals = iter.value()->blockSignals(true); @@ -1628,7 +1673,7 @@ void Window::setupMenu(QMenuBar* menubar) { #ifdef USE_DEBUGGERS m_actions.addAction(tr("Open debugger console..."), "debuggerWindow", this, &Window::consoleOpen, "tools"); #ifdef USE_GDB_STUB - Action* gdbWindow = addGameAction(tr("Start &GDB server..."), "gdbWindow", this, &Window::gdbOpen, "tools"); + auto gdbWindow = addGameAction(tr("Start &GDB server..."), "gdbWindow", this, &Window::gdbOpen, "tools"); m_platformActions.insert(mPLATFORM_GBA, gdbWindow); #endif #endif @@ -1662,6 +1707,10 @@ void Window::setupMenu(QMenuBar* menubar) { addGameAction(tr("Search memory..."), "memorySearch", openControllerTView(), "stateViews"); addGameAction(tr("View &I/O registers..."), "ioViewer", openControllerTView(), "stateViews"); +#ifdef USE_DEBUGGERS + addGameAction(tr("Log memory &accesses..."), "memoryAccessView", openControllerTView(), "tools"); +#endif + #if defined(USE_FFMPEG) && defined(M_CORE_GBA) m_actions.addSeparator("tools"); m_actions.addAction(tr("Convert e-Reader card image to raw..."), "parseCard", this, &Window::parseCard, "tools"); @@ -1679,7 +1728,7 @@ void Window::setupMenu(QMenuBar* menubar) { if (m_controller) { mCheatPressButton(m_controller->cheatDevice(), held); } - }, "tools", QKeySequence(Qt::Key_Apostrophe)); + }, "tools"); m_actions.addHiddenMenu(tr("Autofire"), "autofire"); m_actions.addHeldAction(tr("Autofire A"), "autofireA", [this](bool held) { @@ -1733,7 +1782,7 @@ void Window::setupMenu(QMenuBar* menubar) { } }, "autofire"); - for (Action* action : m_gameActions) { + for (auto& action : m_gameActions) { action->setEnabled(false); } @@ -1797,6 +1846,11 @@ void Window::setupOptions() { reloadConfig(); }, this); + ConfigOption* rewindBufferInterval = m_config->addOption("rewindBufferInterval"); + rewindBufferInterval->connect([this](const QVariant&) { + reloadConfig(); + }, this); + ConfigOption* allowOpposingDirections = m_config->addOption("allowOpposingDirections"); allowOpposingDirections->connect([this](const QVariant&) { reloadConfig(); @@ -1854,6 +1908,11 @@ void Window::setupOptions() { videoScale->connect([this](const QVariant& value) { if (m_display) { m_display->setVideoScale(value.toInt()); +#ifdef ENABLE_SCRIPTING + if (m_controller && m_scripting) { + m_scripting->updateVideoScale(); + } +#endif } }, this); @@ -1862,11 +1921,25 @@ void Window::setupOptions() { updateTitle(); }, this); + ConfigOption* backgroundImage = m_config->addOption("backgroundImage"); + backgroundImage->connect([this](const QVariant& value) { + if (m_display) { + m_display->setBackgroundImage(QImage{value.toString()}); + } + }, this); + m_config->updateOption("backgroundImage"); } void Window::attachWidget(QWidget* widget) { + // Fix https://mgba.io/i/2885 -- seems like a Qt bug + if (m_display && widget != m_display.get()) { + m_display->hide(); + } takeCentralWidget(); setCentralWidget(widget); + if (m_display && widget == m_display.get()) { + m_display->show(); + } } void Window::detachWidget() { @@ -1908,8 +1981,8 @@ void Window::updateMRU() { m_actions.rebuildMenu(menuBar(), this, *m_shortcutController); } -Action* Window::addGameAction(const QString& visibleName, const QString& name, Action::Function function, const QString& menu, const QKeySequence& shortcut) { - Action* action = m_actions.addAction(visibleName, name, [this, function]() { +std::shared_ptr Window::addGameAction(const QString& visibleName, const QString& name, Action::Function function, const QString& menu, const QKeySequence& shortcut) { + auto action = m_actions.addAction(visibleName, name, [this, function = std::move(function)]() { if (m_controller) { function(); } @@ -1919,21 +1992,21 @@ Action* Window::addGameAction(const QString& visibleName, const QString& name, A } template -Action* Window::addGameAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) { +std::shared_ptr Window::addGameAction(const QString& visibleName, const QString& name, T* obj, V (T::*method)(), const QString& menu, const QKeySequence& shortcut) { return addGameAction(visibleName, name, [obj, method]() { (obj->*method)(); }, menu, shortcut); } template -Action* Window::addGameAction(const QString& visibleName, const QString& name, V (CoreController::*method)(), const QString& menu, const QKeySequence& shortcut) { +std::shared_ptr Window::addGameAction(const QString& visibleName, const QString& name, V (CoreController::*method)(), const QString& menu, const QKeySequence& shortcut) { return addGameAction(visibleName, name, [this, method]() { (m_controller.get()->*method)(); }, menu, shortcut); } -Action* Window::addGameAction(const QString& visibleName, const QString& name, Action::BooleanFunction function, const QString& menu, const QKeySequence& shortcut) { - Action* action = m_actions.addBooleanAction(visibleName, name, [this, function](bool value) { +std::shared_ptr Window::addGameAction(const QString& visibleName, const QString& name, Action::BooleanFunction function, const QString& menu, const QKeySequence& shortcut) { + auto action = m_actions.addBooleanAction(visibleName, name, [this, function = std::move(function)](bool value) { if (m_controller) { function(value); } @@ -1999,7 +2072,6 @@ void Window::setController(CoreController* controller, const QString& fname) { } m_controller = std::shared_ptr(controller); - m_inputController.recalibrateAxes(); m_controller->setInputController(&m_inputController); m_controller->setLogger(&m_log); @@ -2012,14 +2084,14 @@ void Window::setController(CoreController* controller, const QString& fname) { }); connect(m_controller.get(), &CoreController::started, this, &Window::gameStarted); - connect(m_controller.get(), &CoreController::started, &m_inputController, &InputController::suspendScreensaver); + connect(m_controller.get(), &CoreController::started, GBAApp::app(), &GBAApp::suspendScreensaver); connect(m_controller.get(), &CoreController::stopping, this, &Window::gameStopped); { connect(m_controller.get(), &CoreController::stopping, [this]() { m_controller.reset(); }); } - connect(m_controller.get(), &CoreController::stopping, &m_inputController, &InputController::resumeScreensaver); + connect(m_controller.get(), &CoreController::stopping, GBAApp::app(), &GBAApp::resumeScreensaver); connect(m_controller.get(), &CoreController::paused, this, &Window::updateFrame); #ifndef Q_OS_MAC @@ -2031,14 +2103,14 @@ void Window::setController(CoreController* controller, const QString& fname) { }); #endif - connect(m_controller.get(), &CoreController::paused, &m_inputController, &InputController::resumeScreensaver); + connect(m_controller.get(), &CoreController::paused, GBAApp::app(), &GBAApp::resumeScreensaver); connect(m_controller.get(), &CoreController::paused, [this]() { emit paused(true); }); connect(m_controller.get(), &CoreController::unpaused, [this]() { emit paused(false); }); - connect(m_controller.get(), &CoreController::unpaused, &m_inputController, &InputController::suspendScreensaver); + connect(m_controller.get(), &CoreController::unpaused, GBAApp::app(), &GBAApp::suspendScreensaver); connect(m_controller.get(), &CoreController::frameAvailable, this, &Window::recordFrame); connect(m_controller.get(), &CoreController::crashed, this, &Window::gameCrashed); connect(m_controller.get(), &CoreController::failed, this, &Window::gameFailed); @@ -2091,6 +2163,8 @@ void Window::setController(CoreController* controller, const QString& fname) { #ifdef ENABLE_SCRIPTING if (m_scripting) { m_scripting->setController(m_controller); + + m_scripting->setVideoBackend(m_display->videoBackend()); } #endif @@ -2110,12 +2184,30 @@ void Window::setController(CoreController* controller, const QString& fname) { m_controller->setPaused(true); m_pendingPause = false; } + +#ifdef ENABLE_SCRIPTING + if (!m_scripting) { + QStringList scripts = m_config->getArgvOption("script").toStringList(); + if (!scripts.isEmpty()) { + scriptingOpen(); + for (const auto& scriptPath : scripts) { + m_scripting->loadFile(scriptPath); + } + } + } +#endif } void Window::attachDisplay() { m_display->attach(m_controller); connect(m_display.get(), &QGBA::Display::drawingStarted, this, &Window::changeRenderer); m_display->startDrawing(m_controller); + +#ifdef ENABLE_SCRIPTING + if (m_scripting) { + m_display->installEventFilter(m_scripting.get()); + } +#endif } void Window::updateMute() { diff --git a/src/platform/qt/Window.h b/src/platform/qt/Window.h index 9495cb3ee..b2e8de82b 100644 --- a/src/platform/qt/Window.h +++ b/src/platform/qt/Window.h @@ -131,7 +131,6 @@ protected: virtual void focusOutEvent(QFocusEvent*) override; virtual void dragEnterEvent(QDragEnterEvent*) override; virtual void dropEvent(QDropEvent*) override; - virtual void mouseDoubleClickEvent(QMouseEvent*) override; private slots: void gameStarted(); @@ -180,10 +179,10 @@ private: template std::function openNamedTView(std::unique_ptr*, A... arg); template std::function openNamedControllerTView(std::unique_ptr*, A... arg); - Action* addGameAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {}); - template Action* addGameAction(const QString& visibleName, const QString& name, T* obj, V (T::*action)(), const QString& menu = {}, const QKeySequence& = {}); - template Action* addGameAction(const QString& visibleName, const QString& name, V (CoreController::*action)(), const QString& menu = {}, const QKeySequence& = {}); - Action* addGameAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {}); + std::shared_ptr addGameAction(const QString& visibleName, const QString& name, Action::Function action, const QString& menu = {}, const QKeySequence& = {}); + template std::shared_ptr addGameAction(const QString& visibleName, const QString& name, T* obj, V (T::*action)(), const QString& menu = {}, const QKeySequence& = {}); + template std::shared_ptr addGameAction(const QString& visibleName, const QString& name, V (CoreController::*action)(), const QString& menu = {}, const QKeySequence& = {}); + std::shared_ptr addGameAction(const QString& visibleName, const QString& name, Action::BooleanFunction action, const QString& menu = {}, const QKeySequence& = {}); void updateTitle(float fps = -1); @@ -199,13 +198,11 @@ private: // TODO: Move these to a new class ActionMapper m_actions; - QList m_gameActions; - QList m_nonMpActions; -#ifdef M_CORE_GBA - QMultiMap m_platformActions; -#endif - Action* m_multiWindow; - QMap m_frameSizes; + QList> m_gameActions; + QList> m_nonMpActions; + QMultiMap> m_platformActions; + std::shared_ptr m_multiWindow; + QMap> m_frameSizes; LogController m_log{0}; LogView* m_logView; diff --git a/src/platform/qt/input/Gamepad.cpp b/src/platform/qt/input/Gamepad.cpp new file mode 100644 index 000000000..183c9c0ab --- /dev/null +++ b/src/platform/qt/input/Gamepad.cpp @@ -0,0 +1,13 @@ +/* Copyright (c) 2013-2023 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 "input/Gamepad.h" + +using namespace QGBA; + +Gamepad::Gamepad(InputDriver* driver, QObject* parent) + : InputSource(driver, parent) +{ +} diff --git a/src/platform/qt/input/Gamepad.h b/src/platform/qt/input/Gamepad.h new file mode 100644 index 000000000..1781885cd --- /dev/null +++ b/src/platform/qt/input/Gamepad.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include "GamepadHatEvent.h" +#include "input/InputSource.h" + +namespace QGBA { + +class InputDriver; + +class Gamepad : public InputSource { +Q_OBJECT + +public: + Gamepad(InputDriver* driver, QObject* parent = nullptr); + + virtual QList currentButtons() = 0; + virtual QList currentAxes() = 0; + virtual QList currentHats() = 0; + + virtual int buttonCount() const = 0; + virtual int axisCount() const = 0; + virtual int hatCount() const = 0; +}; + +} diff --git a/src/platform/qt/GamepadAxisEvent.cpp b/src/platform/qt/input/GamepadAxisEvent.cpp similarity index 78% rename from src/platform/qt/GamepadAxisEvent.cpp rename to src/platform/qt/input/GamepadAxisEvent.cpp index 937e055ed..396574720 100644 --- a/src/platform/qt/GamepadAxisEvent.cpp +++ b/src/platform/qt/input/GamepadAxisEvent.cpp @@ -1,9 +1,9 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 "GamepadAxisEvent.h" +#include "input/GamepadAxisEvent.h" #include "InputController.h" @@ -16,11 +16,11 @@ GamepadAxisEvent::GamepadAxisEvent(int axis, Direction direction, bool isNew, in , m_axis(axis) , m_direction(direction) , m_isNew(isNew) - , m_key(GBA_KEY_NONE) + , m_key(-1) { ignore(); if (controller) { - m_key = static_cast(mInputMapAxis(controller->map(), type, axis, direction * INT_MAX)); + m_key = mInputMapAxis(controller->map(), type, axis, direction * INT_MAX); } } diff --git a/src/platform/qt/GamepadAxisEvent.h b/src/platform/qt/input/GamepadAxisEvent.h similarity index 89% rename from src/platform/qt/GamepadAxisEvent.h rename to src/platform/qt/input/GamepadAxisEvent.h index 75d887425..3f88f4be0 100644 --- a/src/platform/qt/GamepadAxisEvent.h +++ b/src/platform/qt/input/GamepadAxisEvent.h @@ -7,8 +7,6 @@ #include -#include - namespace QGBA { class InputController; @@ -26,7 +24,7 @@ public: int axis() const { return m_axis; } Direction direction() const { return m_direction; } bool isNew() const { return m_isNew; } - GBAKey gbaKey() const { return m_key; } + int platformKey() const { return m_key; } static enum Type Type(); @@ -36,7 +34,7 @@ private: int m_axis; Direction m_direction; bool m_isNew; - GBAKey m_key; + int m_key; }; } diff --git a/src/platform/qt/GamepadButtonEvent.cpp b/src/platform/qt/input/GamepadButtonEvent.cpp similarity index 83% rename from src/platform/qt/GamepadButtonEvent.cpp rename to src/platform/qt/input/GamepadButtonEvent.cpp index 6657a2c69..5ad9ba8f1 100644 --- a/src/platform/qt/GamepadButtonEvent.cpp +++ b/src/platform/qt/input/GamepadButtonEvent.cpp @@ -1,9 +1,9 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 "GamepadButtonEvent.h" +#include "input/GamepadButtonEvent.h" #include "InputController.h" @@ -15,11 +15,11 @@ QEvent::Type GamepadButtonEvent::s_upType = QEvent::None; GamepadButtonEvent::GamepadButtonEvent(QEvent::Type pressType, int button, int type, InputController* controller) : QEvent(pressType) , m_button(button) - , m_key(GBA_KEY_NONE) + , m_key(-1) { ignore(); if (controller) { - m_key = static_cast(mInputMapKey(controller->map(), type, button)); + m_key = mInputMapKey(controller->map(), type, button); } } diff --git a/src/platform/qt/GamepadButtonEvent.h b/src/platform/qt/input/GamepadButtonEvent.h similarity index 81% rename from src/platform/qt/GamepadButtonEvent.h rename to src/platform/qt/input/GamepadButtonEvent.h index 5ba444490..ed2200d91 100644 --- a/src/platform/qt/GamepadButtonEvent.h +++ b/src/platform/qt/input/GamepadButtonEvent.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 @@ -7,8 +7,6 @@ #include -#include - namespace QGBA { class InputController; @@ -18,7 +16,7 @@ public: GamepadButtonEvent(Type pressType, int button, int type, InputController* controller = nullptr); int value() const { return m_button; } - GBAKey gbaKey() const { return m_key; } + int platformKey() const { return m_key; } static Type Down(); static Type Up(); @@ -28,7 +26,7 @@ private: static Type s_upType; int m_button; - GBAKey m_key; + int m_key; }; } diff --git a/src/platform/qt/GamepadHatEvent.cpp b/src/platform/qt/input/GamepadHatEvent.cpp similarity index 83% rename from src/platform/qt/GamepadHatEvent.cpp rename to src/platform/qt/input/GamepadHatEvent.cpp index 052783e8e..25033997f 100644 --- a/src/platform/qt/GamepadHatEvent.cpp +++ b/src/platform/qt/input/GamepadHatEvent.cpp @@ -1,9 +1,9 @@ -/* Copyright (c) 2013-2017 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 "GamepadHatEvent.h" +#include "input/GamepadHatEvent.h" #include "InputController.h" @@ -16,11 +16,11 @@ GamepadHatEvent::GamepadHatEvent(QEvent::Type pressType, int hatId, Direction di : QEvent(pressType) , m_hatId(hatId) , m_direction(direction) - , m_key(GBA_KEY_NONE) + , m_keys(0) { ignore(); if (controller) { - m_key = static_cast(mInputMapHat(controller->map(), type, hatId, direction)); + m_keys = mInputMapHat(controller->map(), type, hatId, direction); } } diff --git a/src/platform/qt/GamepadHatEvent.h b/src/platform/qt/input/GamepadHatEvent.h similarity index 89% rename from src/platform/qt/GamepadHatEvent.h rename to src/platform/qt/input/GamepadHatEvent.h index ecaf1cd2b..c6c49fe3c 100644 --- a/src/platform/qt/GamepadHatEvent.h +++ b/src/platform/qt/input/GamepadHatEvent.h @@ -7,8 +7,6 @@ #include -#include - namespace QGBA { class InputController; @@ -27,7 +25,7 @@ public: int hatId() const { return m_hatId; } Direction direction() const { return m_direction; } - GBAKey gbaKey() const { return m_key; } + int platformKeys() const { return m_keys; } static Type Down(); static Type Up(); @@ -38,7 +36,7 @@ private: int m_hatId; Direction m_direction; - GBAKey m_key; + int m_keys; }; } diff --git a/src/platform/qt/input/InputDriver.cpp b/src/platform/qt/input/InputDriver.cpp new file mode 100644 index 000000000..3f805f411 --- /dev/null +++ b/src/platform/qt/input/InputDriver.cpp @@ -0,0 +1,103 @@ +/* Copyright (c) 2013-2023 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 "input/InputDriver.h" + +using namespace QGBA; + +InputDriver::InputDriver(QObject* parent) + : QObject(parent) +{} + +void InputDriver::loadConfiguration(ConfigController*) { +} + +void InputDriver::saveConfiguration(ConfigController*) { +} + +bool InputDriver::supportsPolling() const { + return false; +} + +bool InputDriver::supportsGamepads() const { + return false; +} + +bool InputDriver::supportsSensors() const { + return false; +} + +void InputDriver::bindDefaults(InputController*) { +} + +QList InputDriver::connectedKeySources() const { + return {}; +} + +QList> InputDriver::connectedGamepads() const { + return {}; +} + +int InputDriver::activeKeySourceIndex() const { + return -1; +} + +int InputDriver::activeGamepadIndex() const { + return -1; +} + +KeySource* InputDriver::activeKeySource() { + QList ks(connectedKeySources()); + int activeKeySource = activeKeySourceIndex(); + if (activeKeySource < 0 || activeKeySource >= ks.count()) { + return nullptr; + } + return ks[activeKeySource]; +} + +std::shared_ptr InputDriver::activeGamepad() { + QList> pads(connectedGamepads()); + int activeGamepad = activeGamepadIndex(); + if (activeGamepad < 0 || activeGamepad >= pads.count()) { + return nullptr; + } + return pads[activeGamepad]; +} + +void InputDriver::setActiveKeySource(int) { +} + +void InputDriver::setActiveGamepad(int) { +} + +void InputDriver::registerTiltAxisX(int) { +} + +void InputDriver::registerTiltAxisY(int) { +} + +void InputDriver::registerGyroAxisX(int) { +} + +void InputDriver::registerGyroAxisY(int) { +} + +void InputDriver::registerGyroAxisZ(int) { +} + +float InputDriver::gyroSensitivity() const { + return 0; +} + +void InputDriver::setGyroSensitivity(float) { +} + +mRumble* InputDriver::rumble() { + return nullptr; +} + +mRotationSource* InputDriver::rotationSource() { + return nullptr; +} diff --git a/src/platform/qt/input/InputDriver.h b/src/platform/qt/input/InputDriver.h new file mode 100644 index 000000000..4b0513f2e --- /dev/null +++ b/src/platform/qt/input/InputDriver.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include +#include +#include + +#include + +struct mRotationSource; +struct mRumble; + +namespace QGBA { + +class ConfigController; +class Gamepad; +class InputController; +class KeySource; + +class InputDriver : public QObject { +Q_OBJECT + +public: + InputDriver(QObject* parent = nullptr); + virtual ~InputDriver() = default; + + virtual uint32_t type() const = 0; + virtual QString visibleName() const = 0; + virtual QString currentProfile() const = 0; + + virtual bool supportsPolling() const; + virtual bool supportsGamepads() const; + virtual bool supportsSensors() const; + + virtual void loadConfiguration(ConfigController*); + virtual void saveConfiguration(ConfigController*); + + virtual void bindDefaults(InputController*); + + virtual bool update() = 0; + + virtual QList connectedKeySources() const; + virtual QList> connectedGamepads() const; + + virtual int activeKeySourceIndex() const; + virtual int activeGamepadIndex() const; + + KeySource* activeKeySource(); + std::shared_ptr activeGamepad(); + + virtual void setActiveKeySource(int); + virtual void setActiveGamepad(int); + + virtual void registerTiltAxisX(int axis); + virtual void registerTiltAxisY(int axis); + virtual void registerGyroAxisX(int axis); + virtual void registerGyroAxisY(int axis); + virtual void registerGyroAxisZ(int axis); + + virtual float gyroSensitivity() const; + virtual void setGyroSensitivity(float sensitivity); + + virtual mRumble* rumble(); + virtual mRotationSource* rotationSource(); +}; + +} diff --git a/src/platform/qt/input/InputMapper.cpp b/src/platform/qt/input/InputMapper.cpp new file mode 100644 index 000000000..c84316efd --- /dev/null +++ b/src/platform/qt/input/InputMapper.cpp @@ -0,0 +1,181 @@ +/* Copyright (c) 2013-2023 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 "input/InputMapper.h" + +#include + +using namespace QGBA; + +InputMapper::InputMapper(mInputMap* map, uint32_t type) + : m_map(map) + , m_type(type) +{ +} + +int InputMapper::mapKey(int key) const { + return mInputMapKey(m_map, m_type, key); +} + +int InputMapper::mapAxis(int axis, int16_t value) const { + return mInputMapAxis(m_map, m_type, axis, value); +} + +int InputMapper::mapHat(int hat, GamepadHatEvent::Direction direction) const { + return mInputMapHat(m_map, m_type, hat, direction); +} + +int InputMapper::mapKeys(QList keys) const { + int platformKeys = 0; + for (int i = 0; i < keys.count(); ++i) { + if (!keys[i]) { + continue; + } + int platformKey = mInputMapKey(m_map, m_type, i); + if (platformKey >= 0) { + platformKeys |= 1 << platformKey; + } + } + return platformKeys; +} + +int InputMapper::mapKeys(QSet keys) const { + int platformKeys = 0; + for (int key : keys) { + int platformKey = mInputMapKey(m_map, m_type, key); + if (platformKey >= 0) { + platformKeys |= 1 << platformKey; + } + } + return platformKeys; +} + +int InputMapper::mapAxes(QList axes) const { + int platformKeys = 0; + for (int i = 0; i < axes.count(); ++i) { + int platformKey = mInputMapAxis(m_map, m_type, i, axes[i]); + if (platformKey >= 0) { + platformKeys |= 1 << platformKey; + } + } + return platformKeys; +} + +int InputMapper::mapHats(QList hats) const { + int platformKeys = 0; + for (int i = 0; i < hats.count(); ++i) { + platformKeys |= mInputMapHat(m_map, m_type, i, hats[i]); + } + return platformKeys; +} + +void InputMapper::bindKey(int key, int platformKey) { + mInputBindKey(m_map, m_type, key, platformKey); +} + +void InputMapper::bindAxis(int axis, GamepadAxisEvent::Direction direction, int platformKey) { + const mInputAxis* old = mInputQueryAxis(m_map, m_type, axis); + mInputAxis description = { -1, -1, -axisThreshold(axis), axisThreshold(axis) }; + if (old) { + description = *old; + } + switch (direction) { + case GamepadAxisEvent::NEGATIVE: + description.lowDirection = platformKey; + description.deadLow = axisCenter(axis) - axisThreshold(axis); + break; + case GamepadAxisEvent::POSITIVE: + description.highDirection = platformKey; + description.deadHigh = axisCenter(axis) + axisThreshold(axis); + break; + default: + return; + } + mInputBindAxis(m_map, m_type, axis, &description); +} + +void InputMapper::bindHat(int hat, GamepadHatEvent::Direction direction, int platformKey) { + mInputHatBindings bindings{ -1, -1, -1, -1 }; + mInputQueryHat(m_map, m_type, hat, &bindings); + switch (direction) { + case GamepadHatEvent::UP: + bindings.up = platformKey; + break; + case GamepadHatEvent::RIGHT: + bindings.right = platformKey; + break; + case GamepadHatEvent::DOWN: + bindings.down = platformKey; + break; + case GamepadHatEvent::LEFT: + bindings.left = platformKey; + break; + default: + return; + } + mInputBindHat(m_map, m_type, hat, &bindings); +} + +QSet InputMapper::queryKeyBindings(int platformKey) const { + return {mInputQueryBinding(m_map, m_type, platformKey)}; +} + +QSet> InputMapper::queryAxisBindings(int platformKey) const { + QPair>> userdata; + userdata.first = platformKey; + + mInputEnumerateAxes(m_map, m_type, [](int axis, const struct mInputAxis* description, void* user) { + auto userdata = static_cast>>*>(user); + int platformKey = userdata->first; + auto& bindings = userdata->second; + + if (description->lowDirection == platformKey) { + bindings.insert({axis, GamepadAxisEvent::NEGATIVE}); + } + if (description->highDirection == platformKey) { + bindings.insert({axis, GamepadAxisEvent::POSITIVE}); + } + }, &userdata); + + return userdata.second; +} + +QSet> InputMapper::queryHatBindings(int platformKey) const { + QPair>> userdata; + userdata.first = platformKey; + + mInputEnumerateHats(m_map, m_type, [](int hat, const struct mInputHatBindings* description, void* user) { + auto userdata = static_cast>>*>(user); + int platformKey = userdata->first; + auto& bindings = userdata->second; + + if (description->up == platformKey) { + bindings.insert({hat, GamepadHatEvent::UP}); + } + if (description->right == platformKey) { + bindings.insert({hat, GamepadHatEvent::RIGHT}); + } + if (description->down == platformKey) { + bindings.insert({hat, GamepadHatEvent::DOWN}); + } + if (description->left == platformKey) { + bindings.insert({hat, GamepadHatEvent::LEFT}); + } + }, &userdata); + + return userdata.second; +} + +void InputMapper::unbindAllKeys() { + mInputUnbindAllKeys(m_map, m_type); +} + +void InputMapper::unbindAllAxes() { + mInputUnbindAllAxes(m_map, m_type); +} + +void InputMapper::unbindAllHats() { + mInputUnbindAllHats(m_map, m_type); +} diff --git a/src/platform/qt/input/InputMapper.h b/src/platform/qt/input/InputMapper.h new file mode 100644 index 000000000..0e8268356 --- /dev/null +++ b/src/platform/qt/input/InputMapper.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include +#include + +#include "GamepadAxisEvent.h" +#include "GamepadHatEvent.h" + +struct mInputMap; + +namespace QGBA { + +class InputMapper final { +public: + static const int32_t DEFAULT_AXIS_THRESHOLD = 0x3000; + + InputMapper(mInputMap* map, uint32_t type); + + mInputMap* inputMap() const { return m_map; } + uint32_t type() const { return m_type; } + + int mapKey(int key) const; + int mapAxis(int axis, int16_t value) const; + int mapHat(int hat, GamepadHatEvent::Direction) const; + + int mapKeys(QList keys) const; + int mapKeys(QSet keys) const; + int mapAxes(QList axes) const; + int mapHats(QList hats) const; + + void bindKey(int key, int platformKey); + void bindAxis(int axis, GamepadAxisEvent::Direction, int platformKey); + void bindHat(int hat, GamepadHatEvent::Direction, int platformKey); + + QSet queryKeyBindings(int platformKey) const; + QSet> queryAxisBindings(int platformKey) const; + QSet> queryHatBindings(int platformKey) const; + + int16_t axisThreshold(int) const { return DEFAULT_AXIS_THRESHOLD; } + int16_t axisCenter(int) const { return 0; } + + void unbindAllKeys(); + void unbindAllAxes(); + void unbindAllHats(); + +private: + mInputMap* m_map; + uint32_t m_type; +}; + +} diff --git a/src/platform/qt/input/InputSource.cpp b/src/platform/qt/input/InputSource.cpp new file mode 100644 index 000000000..ec1dc8bc5 --- /dev/null +++ b/src/platform/qt/input/InputSource.cpp @@ -0,0 +1,14 @@ +/* Copyright (c) 2013-2023 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 "input/InputSource.h" + +using namespace QGBA; + +InputSource::InputSource(InputDriver* driver, QObject* parent) + : QObject(parent) + , m_driver(driver) +{ +} diff --git a/src/platform/qt/input/InputSource.h b/src/platform/qt/input/InputSource.h new file mode 100644 index 000000000..3bf7350d7 --- /dev/null +++ b/src/platform/qt/input/InputSource.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include +#include + +#include "input/InputDriver.h" + +namespace QGBA { + +class InputSource : public QObject { +Q_OBJECT + +public: + InputSource(InputDriver* driver, QObject* parent = nullptr); + virtual ~InputSource() = default; + + InputDriver* driver() { return m_driver; } + uint32_t type() { return m_driver->type(); } + + virtual QString name() const = 0; + virtual QString visibleName() const = 0; + +protected: + InputDriver* const m_driver; +}; + +} diff --git a/src/platform/qt/input/KeySource.cpp b/src/platform/qt/input/KeySource.cpp new file mode 100644 index 000000000..32f0ca740 --- /dev/null +++ b/src/platform/qt/input/KeySource.cpp @@ -0,0 +1,13 @@ +/* Copyright (c) 2013-2023 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 "input/KeySource.h" + +using namespace QGBA; + +KeySource::KeySource(InputDriver* driver, QObject* parent) + : InputSource(driver, parent) +{ +} diff --git a/src/platform/qt/input/KeySource.h b/src/platform/qt/input/KeySource.h new file mode 100644 index 000000000..e3df912a6 --- /dev/null +++ b/src/platform/qt/input/KeySource.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include "input/InputSource.h" + +namespace QGBA { + +class InputDriver; + +class KeySource : public InputSource { +Q_OBJECT + +public: + KeySource(InputDriver* driver, QObject* parent = nullptr); + + virtual QSet currentKeys() = 0; +}; + +} diff --git a/src/platform/qt/input/SDLInputDriver.cpp b/src/platform/qt/input/SDLInputDriver.cpp new file mode 100644 index 000000000..e3a77094f --- /dev/null +++ b/src/platform/qt/input/SDLInputDriver.cpp @@ -0,0 +1,363 @@ +/* Copyright (c) 2013-2023 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 "input/SDLInputDriver.h" + +#include "ConfigController.h" +#include "InputController.h" + +#include + +using namespace QGBA; + +int s_sdlInited = 0; +mSDLEvents s_sdlEvents; + +void SDL::suspendScreensaver() { +#if SDL_VERSION_ATLEAST(2, 0, 0) + if (s_sdlInited) { + mSDLSuspendScreensaver(&s_sdlEvents); + } +#endif +} + +void SDL::resumeScreensaver() { +#if SDL_VERSION_ATLEAST(2, 0, 0) + if (s_sdlInited) { + mSDLResumeScreensaver(&s_sdlEvents); + } +#endif +} + +void SDL::setScreensaverSuspendable(bool suspendable) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + if (s_sdlInited) { + mSDLSetScreensaverSuspendable(&s_sdlEvents, suspendable); + } +#endif +} + +SDLInputDriver::SDLInputDriver(InputController* controller, QObject* parent) + : InputDriver(parent) + , m_controller(controller) +{ + if (s_sdlInited == 0) { + mSDLInitEvents(&s_sdlEvents); + } + ++s_sdlInited; + m_sdlPlayer.bindings = m_controller->map(); + + for (size_t i = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) { + m_gamepads.append(std::make_shared(this, i)); + } +} + +SDLInputDriver::~SDLInputDriver() { + if (m_playerAttached) { + mSDLDetachPlayer(&s_sdlEvents, &m_sdlPlayer); + } + + --s_sdlInited; + if (s_sdlInited == 0) { + mSDLDeinitEvents(&s_sdlEvents); + } +} + +bool SDLInputDriver::supportsPolling() const { + return true; +} + +bool SDLInputDriver::supportsGamepads() const { + return true; +} + +bool SDLInputDriver::supportsSensors() const { + return true; +} + +QString SDLInputDriver::currentProfile() const { + if (m_sdlPlayer.joystick) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + return SDL_JoystickName(m_sdlPlayer.joystick->joystick); +#else + return SDL_JoystickName(SDL_JoystickIndex(m_sdlPlayer.joystick->joystick)); +#endif + } + return {}; +} + +void SDLInputDriver::loadConfiguration(ConfigController* config) { + m_config = config; + mSDLEventsLoadConfig(&s_sdlEvents, config->input()); + if (!m_playerAttached) { + m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer); + } + if (m_playerAttached) { + mSDLPlayerLoadConfig(&m_sdlPlayer, config->input()); + } +} + +void SDLInputDriver::saveConfiguration(ConfigController* config) { + if (m_playerAttached) { + mSDLPlayerSaveConfig(&m_sdlPlayer, config->input()); + } +} + +void SDLInputDriver::bindDefaults(InputController* controller) { + mSDLInitBindingsGBA(controller->map()); +} + +mRumble* SDLInputDriver::rumble() { +#if SDL_VERSION_ATLEAST(2, 0, 0) + if (m_playerAttached) { + return &m_sdlPlayer.rumble.d; + } +#endif + return nullptr; +} + +mRotationSource* SDLInputDriver::rotationSource() { + if (m_playerAttached) { + return &m_sdlPlayer.rotation.d; + } + return nullptr; +} + + +bool SDLInputDriver::update() { + if (!m_playerAttached) { + return false; + } + + SDL_JoystickUpdate(); +#if SDL_VERSION_ATLEAST(2, 0, 0) + updateGamepads(); +#endif + + return true; +} + +QList> SDLInputDriver::connectedGamepads() const { + QList> pads; + for (auto& pad : m_gamepads) { + pads.append(pad); + } + return pads; +} + +#if SDL_VERSION_ATLEAST(2, 0, 0) +void SDLInputDriver::updateGamepads() { + if (m_config) { + mSDLUpdateJoysticks(&s_sdlEvents, m_config->input()); + } + for (int i = 0; i < m_gamepads.size(); ++i) { + if (m_gamepads.at(i)->updateIndex()) { + continue; + } + m_gamepads.removeAt(i); + --i; + } + std::sort(m_gamepads.begin(), m_gamepads.end(), [](const auto& a, const auto b) { + return a->m_index < b->m_index; + }); + + for (size_t i = 0, j = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) { + if ((ssize_t) j < m_gamepads.size()) { + std::shared_ptr gamepad = m_gamepads.at(j); + if (gamepad->m_index == i) { + ++j; + continue; + } + } + m_gamepads.append(std::make_shared(this, i)); + } + std::sort(m_gamepads.begin(), m_gamepads.end(), [](const auto& a, const auto b) { + return a->m_index < b->m_index; + }); +} +#endif + +int SDLInputDriver::activeGamepadIndex() const { + return m_sdlPlayer.joystick ? m_sdlPlayer.joystick->index : 0; +} + +void SDLInputDriver::setActiveGamepad(int index) { + mSDLPlayerChangeJoystick(&s_sdlEvents, &m_sdlPlayer, index); +} + +void SDLInputDriver::registerTiltAxisX(int axis) { + if (m_playerAttached) { + m_sdlPlayer.rotation.axisX = axis; + } +} + +void SDLInputDriver::registerTiltAxisY(int axis) { + if (m_playerAttached) { + m_sdlPlayer.rotation.axisY = axis; + } +} + +void SDLInputDriver::registerGyroAxisX(int axis) { + if (m_playerAttached) { + m_sdlPlayer.rotation.gyroX = axis; + if (m_sdlPlayer.rotation.gyroY == axis) { + m_sdlPlayer.rotation.gyroZ = axis; + } else { + m_sdlPlayer.rotation.gyroZ = -1; + } + } +} + +void SDLInputDriver::registerGyroAxisY(int axis) { + if (m_playerAttached) { + m_sdlPlayer.rotation.gyroY = axis; + if (m_sdlPlayer.rotation.gyroX == axis) { + m_sdlPlayer.rotation.gyroZ = axis; + } else { + m_sdlPlayer.rotation.gyroZ = -1; + } + } +} + +void SDLInputDriver::registerGyroAxisZ(int axis) { + if (m_playerAttached) { + m_sdlPlayer.rotation.gyroZ = axis; + m_sdlPlayer.rotation.gyroX = -1; + m_sdlPlayer.rotation.gyroY = -1; + } +} + +float SDLInputDriver::gyroSensitivity() const { + if (m_playerAttached) { + return m_sdlPlayer.rotation.gyroSensitivity; + } + return 0; +} + +void SDLInputDriver::setGyroSensitivity(float sensitivity) { + if (m_playerAttached) { + m_sdlPlayer.rotation.gyroSensitivity = sensitivity; + } +} + +SDLGamepad::SDLGamepad(SDLInputDriver* driver, int index, QObject* parent) + : Gamepad(driver, parent) + , m_index(index) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), m_guid, sizeof(m_guid)); +#endif +} + +QList SDLGamepad::currentButtons() { + if (!verify()) { + return {}; + } + + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + QList buttons; + + int numButtons = SDL_JoystickNumButtons(joystick); + for (int i = 0; i < numButtons; ++i) { + buttons.append(SDL_JoystickGetButton(joystick, i)); + } + + return buttons; +} + +QList SDLGamepad::currentAxes() { + if (!verify()) { + return {}; + } + + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + QList axes; + + int numAxes = SDL_JoystickNumAxes(joystick); + for (int i = 0; i < numAxes; ++i) { + axes.append(SDL_JoystickGetAxis(joystick, i)); + } + + return axes; +} + +QList SDLGamepad::currentHats() { + if (!verify()) { + return {}; + } + + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + QList hats; + + int numHats = SDL_JoystickNumHats(joystick); + for (int i = 0; i < numHats; ++i) { + hats.append(static_cast(SDL_JoystickGetHat(joystick, i))); + } + + return hats; +} + +int SDLGamepad::buttonCount() const { + if (!verify()) { + return -1; + } + + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + return SDL_JoystickNumButtons(joystick); +} + +int SDLGamepad::axisCount() const { + if (!verify()) { + return -1; + } + + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + return SDL_JoystickNumAxes(joystick); +} + +int SDLGamepad::hatCount() const { + if (!verify()) { + return -1; + } + + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick; + return SDL_JoystickNumHats(joystick); +} + +QString SDLGamepad::name() const { +#if SDL_VERSION_ATLEAST(2, 0, 0) + return m_guid; +#else + return visibleName(); +#endif +} + +QString SDLGamepad::visibleName() const { +#if SDL_VERSION_ATLEAST(2, 0, 0) + return SDL_JoystickName(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick); +#else + return SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, m_index)->joystick)); +#endif +} + +#if SDL_VERSION_ATLEAST(2, 0, 0) +bool SDLGamepad::updateIndex() { + char guid[34]; + for (size_t i = 0; i < SDL_JoystickListSize(&s_sdlEvents.joysticks); ++i) { + SDL_Joystick* joystick = SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, i)->joystick; + SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), guid, sizeof(guid)); + if (memcmp(guid, m_guid, 33) == 0) { + m_index = i; + return true; + } + } + return false; +} +#endif + +bool SDLGamepad::verify() const { + return m_index < SDL_JoystickListSize(&s_sdlEvents.joysticks); +} diff --git a/src/platform/qt/input/SDLInputDriver.h b/src/platform/qt/input/SDLInputDriver.h new file mode 100644 index 000000000..61f1e6238 --- /dev/null +++ b/src/platform/qt/input/SDLInputDriver.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2013-2023 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/. */ +#pragma once + +#include "input/Gamepad.h" +#include "input/InputDriver.h" + +#include "platform/sdl/sdl-events.h" + +#include + +namespace QGBA { + +class SDLGamepad; + +namespace SDL { + void suspendScreensaver(); + void resumeScreensaver(); + void setScreensaverSuspendable(bool); +} + +class SDLInputDriver : public InputDriver { +Q_OBJECT + +public: + SDLInputDriver(InputController*, QObject* parent = nullptr); + ~SDLInputDriver(); + + uint32_t type() const override { return SDL_BINDING_BUTTON; } + QString visibleName() const override { return QLatin1String("SDL"); } + QString currentProfile() const override; + + bool supportsPolling() const override; + bool supportsGamepads() const override; + bool supportsSensors() const override; + + void loadConfiguration(ConfigController* config) override; + void saveConfiguration(ConfigController* config) override; + + void bindDefaults(InputController*) override; + + bool update() override; + + QList> connectedGamepads() const override; + + int activeGamepadIndex() const override; + void setActiveGamepad(int) override; + + void registerTiltAxisX(int axis) override; + void registerTiltAxisY(int axis) override; + void registerGyroAxisX(int axis) override; + void registerGyroAxisY(int axis) override; + void registerGyroAxisZ(int axis) override; + + float gyroSensitivity() const override; + void setGyroSensitivity(float sensitivity) override; + + mRumble* rumble() override; + mRotationSource* rotationSource() override; + +private: + ConfigController* m_config = nullptr; + InputController* m_controller; + mSDLPlayer m_sdlPlayer{}; + bool m_playerAttached = false; + QList> m_gamepads; + +#if SDL_VERSION_ATLEAST(2, 0, 0) + void updateGamepads(); +#endif +}; + +class SDLGamepad : public Gamepad { +Q_OBJECT + +public: + SDLGamepad(SDLInputDriver*, int index, QObject* parent = nullptr); + + QList currentButtons() override; + QList currentAxes() override; + QList currentHats() override; + + int buttonCount() const override; + int axisCount() const override; + int hatCount() const override; + + QString name() const override; + QString visibleName() const override; + +#if SDL_VERSION_ATLEAST(2, 0, 0) + bool updateIndex(); +#endif + +private: + friend class SDLInputDriver; + + size_t m_index; +#if SDL_VERSION_ATLEAST(2, 0, 0) + char m_guid[34]{}; +#endif + + bool verify() const; +}; + +} diff --git a/src/platform/qt/main.cpp b/src/platform/qt/main.cpp index 67668b011..c245cff53 100644 --- a/src/platform/qt/main.cpp +++ b/src/platform/qt/main.cpp @@ -14,6 +14,10 @@ #include #include +#ifdef BUILD_SDL +#include "platform/sdl/sdl-events.h" +#endif + #include #include @@ -24,6 +28,7 @@ #ifdef QT_STATIC #include #ifdef Q_OS_WIN +Q_IMPORT_PLUGIN(QJpegPlugin); Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin); #ifdef BUILD_QT_MULTIMEDIA @@ -38,6 +43,7 @@ Q_IMPORT_PLUGIN(AVFServicePlugin); #endif #elif defined(Q_OS_UNIX) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); +Q_IMPORT_PLUGIN(QWaylandIntegrationPlugin); #endif #endif @@ -98,6 +104,10 @@ int main(int argc, char* argv[]) { QApplication::setWindowIcon(QIcon(":/res/mgba-256.png")); #endif +#ifdef Q_OS_UNIX + QApplication::setDesktopFileName(QString("io.mgba.mGBA")); +#endif + QTranslator qtTranslator; qtTranslator.load(locale, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath)); application.installTranslator(&qtTranslator); diff --git a/src/platform/qt/scripting/ScriptingController.cpp b/src/platform/qt/scripting/ScriptingController.cpp index cd1e716d4..065754bf1 100644 --- a/src/platform/qt/scripting/ScriptingController.cpp +++ b/src/platform/qt/scripting/ScriptingController.cpp @@ -5,10 +5,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "scripting/ScriptingController.h" +#include +#include +#include +#include + #include "CoreController.h" +#include "Display.h" +#include "input/Gamepad.h" +#include "input/GamepadButtonEvent.h" +#include "input/GamepadHatEvent.h" +#include "InputController.h" #include "scripting/ScriptingTextBuffer.h" #include "scripting/ScriptingTextBufferModel.h" +#include +#include +#include + using namespace QGBA; ScriptingController::ScriptingController(QObject* parent) @@ -37,12 +51,18 @@ ScriptingController::ScriptingController(QObject* parent) m_bufferModel = new ScriptingTextBufferModel(this); QObject::connect(m_bufferModel, &ScriptingTextBufferModel::textBufferCreated, this, &ScriptingController::textBufferCreated); + connect(&m_storageFlush, &QTimer::timeout, this, &ScriptingController::flushStorage); + m_storageFlush.setInterval(5); + + mScriptGamepadInit(&m_gamepad); + init(); } ScriptingController::~ScriptingController() { clearController(); mScriptContextDeinit(&m_scriptContext); + mScriptGamepadDeinit(&m_gamepad); } void ScriptingController::setController(std::shared_ptr controller) { @@ -50,15 +70,31 @@ void ScriptingController::setController(std::shared_ptr controll return; } clearController(); - m_controller = controller; + if (!controller) { + return; + } + m_controller = std::move(controller); CoreController::Interrupter interrupter(m_controller); m_controller->thread()->scriptContext = &m_scriptContext; if (m_controller->hasStarted()) { - mScriptContextAttachCore(&m_scriptContext, m_controller->thread()->core); + attach(); } + updateVideoScale(); connect(m_controller.get(), &CoreController::stopping, this, &ScriptingController::clearController); } +void ScriptingController::setInputController(InputController* input) { + if (m_inputController) { + m_inputController->disconnect(this); + } + m_inputController = input; + connect(m_inputController, &InputController::updated, this, &ScriptingController::updateGamepad); +} + +void ScriptingController::setVideoBackend(VideoBackend* backend) { + mScriptCanvasUpdateBackend(&m_scriptContext, backend); +} + bool ScriptingController::loadFile(const QString& path) { VFileDevice vf(path, QIODevice::ReadOnly); if (!vf.isOpen()) { @@ -73,11 +109,21 @@ bool ScriptingController::load(VFileDevice& vf, const QString& name) { } QByteArray utf8 = name.toUtf8(); CoreController::Interrupter interrupter(m_controller); - if (!m_activeEngine->load(m_activeEngine, utf8.constData(), vf) || !m_activeEngine->run(m_activeEngine)) { - emit error(QString::fromUtf8(m_activeEngine->getError(m_activeEngine))); - return false; + if (m_controller) { + m_controller->setSync(false); + m_controller->unpaused(); } - return true; + bool ok = true; + if (!m_activeEngine->load(m_activeEngine, utf8.constData(), vf) || !m_activeEngine->run(m_activeEngine)) { + ok = false; + } + if (m_controller) { + m_controller->setSync(true); + if (m_controller->isPaused()) { + m_controller->paused(); + } + } + return ok; } void ScriptingController::clearController() { @@ -92,6 +138,13 @@ void ScriptingController::clearController() { m_controller.reset(); } +void ScriptingController::updateVideoScale() { + if (!m_controller) { + return; + } + mScriptCanvasSetInternalScale(&m_scriptContext, m_controller->videoScale()); +} + void ScriptingController::reset() { CoreController::Interrupter interrupter(m_controller); m_bufferModel->reset(); @@ -101,7 +154,7 @@ void ScriptingController::reset() { m_activeEngine = nullptr; init(); if (m_controller && m_controller->hasStarted()) { - mScriptContextAttachCore(&m_scriptContext, m_controller->thread()->core); + attach(); } } @@ -110,10 +163,178 @@ void ScriptingController::runCode(const QString& code) { load(vf, "*prompt"); } +void ScriptingController::flushStorage() { +#ifdef USE_JSON_C + mScriptStorageFlushAll(&m_scriptContext); +#endif +} + +bool ScriptingController::eventFilter(QObject* obj, QEvent* ev) { + event(obj, ev); + return false; +} + +void ScriptingController::event(QObject* obj, QEvent* event) { + if (!m_controller) { + return; + } + + CoreController::Interrupter interrupter(m_controller); + + switch (event->type()) { + case QEvent::FocusOut: + case QEvent::WindowDeactivate: + mScriptContextClearKeys(&m_scriptContext); + return; + case QEvent::KeyPress: + case QEvent::KeyRelease: { + struct mScriptKeyEvent ev{mSCRIPT_EV_TYPE_KEY}; + auto keyEvent = static_cast(event); + ev.state = event->type() == QEvent::KeyRelease ? mSCRIPT_INPUT_STATE_UP : + static_cast(event)->isAutoRepeat() ? mSCRIPT_INPUT_STATE_HELD : mSCRIPT_INPUT_STATE_DOWN; + ev.key = qtToScriptingKey(keyEvent); + ev.modifiers = qtToScriptingModifiers(keyEvent->modifiers()); + mScriptContextFireEvent(&m_scriptContext, &ev.d); + return; + } + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: { + struct mScriptMouseButtonEvent ev{mSCRIPT_EV_TYPE_MOUSE_BUTTON}; + auto mouseEvent = static_cast(event); + ev.mouse = 0; + ev.state = event->type() == QEvent::MouseButtonPress ? mSCRIPT_INPUT_STATE_DOWN : mSCRIPT_INPUT_STATE_UP; + ev.button = 31 - clz32(mouseEvent->button()); + mScriptContextFireEvent(&m_scriptContext, &ev.d); + return; + } + case QEvent::MouseMove: { + struct mScriptMouseMoveEvent ev{mSCRIPT_EV_TYPE_MOUSE_MOVE}; + auto mouseEvent = static_cast(event); + QPoint pos = mouseEvent->pos(); + pos = static_cast(obj)->normalizedPoint(m_controller.get(), pos); + ev.mouse = 0; + ev.x = pos.x(); + ev.y = pos.y(); + mScriptContextFireEvent(&m_scriptContext, &ev.d); + return; + } + case QEvent::Wheel: { + struct mScriptMouseWheelEvent ev{mSCRIPT_EV_TYPE_MOUSE_WHEEL}; + auto wheelEvent = static_cast(event); + QPoint adelta = wheelEvent->angleDelta(); + QPoint pdelta = wheelEvent->pixelDelta(); + ev.mouse = 0; + if (!pdelta.isNull()) { + ev.x = pdelta.x(); + ev.y = pdelta.y(); + } else { + ev.x = adelta.x(); + ev.y = adelta.y(); + } + mScriptContextFireEvent(&m_scriptContext, &ev.d); + return; + } + default: + break; + } + + auto type = event->type(); + if (type == GamepadButtonEvent::Down() || type == GamepadButtonEvent::Up()) { + struct mScriptGamepadButtonEvent ev{mSCRIPT_EV_TYPE_GAMEPAD_BUTTON}; + auto gamepadEvent = static_cast(event); + ev.pad = 0; + ev.state = event->type() == GamepadButtonEvent::Down() ? mSCRIPT_INPUT_STATE_DOWN : mSCRIPT_INPUT_STATE_UP; + ev.button = gamepadEvent->value(); + mScriptContextFireEvent(&m_scriptContext, &ev.d); + } + if (type == GamepadHatEvent::Type()) { + struct mScriptGamepadHatEvent ev{mSCRIPT_EV_TYPE_GAMEPAD_HAT}; + updateGamepad(); + auto gamepadEvent = static_cast(event); + ev.pad = 0; + ev.hat = gamepadEvent->hatId(); + ev.direction = gamepadEvent->direction(); + mScriptContextFireEvent(&m_scriptContext, &ev.d); + } +} + +void ScriptingController::updateGamepad() { + InputDriver* driver = m_inputController->gamepadDriver(); + if (!driver) { + detachGamepad(); + return; + } + std::shared_ptr gamepad = driver->activeGamepad(); + if (!gamepad) { + detachGamepad(); + return; + } + + QString name = gamepad->name(); + strlcpy(m_gamepad.internalName, name.toUtf8().constData(), sizeof(m_gamepad.internalName)); + name = gamepad->visibleName(); + strlcpy(m_gamepad.visibleName, name.toUtf8().constData(), sizeof(m_gamepad.visibleName)); + attachGamepad(); + + QList buttons = gamepad->currentButtons(); + int nButtons = gamepad->buttonCount(); + mScriptGamepadSetButtonCount(&m_gamepad, nButtons); + for (int i = 0; i < nButtons; ++i) { + mScriptGamepadSetButton(&m_gamepad, i, buttons.at(i)); + } + + QList axes = gamepad->currentAxes(); + int nAxes = gamepad->axisCount(); + mScriptGamepadSetAxisCount(&m_gamepad, nAxes); + for (int i = 0; i < nAxes; ++i) { + mScriptGamepadSetAxis(&m_gamepad, i, axes.at(i)); + } + + QList hats = gamepad->currentHats(); + int nHats = gamepad->hatCount(); + mScriptGamepadSetHatCount(&m_gamepad, nHats); + for (int i = 0; i < nHats; ++i) { + mScriptGamepadSetHat(&m_gamepad, i, hats.at(i)); + } +} + +void ScriptingController::attach() { + CoreController::Interrupter interrupter(m_controller); + mScriptContextAttachCore(&m_scriptContext, m_controller->thread()->core); +#ifdef USE_DEBUGGERS + m_controller->attachDebugger(false); +#endif +} + +void ScriptingController::attachGamepad() { + mScriptGamepad* pad = mScriptContextGamepadLookup(&m_scriptContext, 0); + if (pad == &m_gamepad) { + return; + } + if (pad) { + mScriptContextGamepadDetach(&m_scriptContext, 0); + } + mScriptContextGamepadAttach(&m_scriptContext, &m_gamepad); +} + +void ScriptingController::detachGamepad() { + mScriptGamepad* pad = mScriptContextGamepadLookup(&m_scriptContext, 0); + if (pad != &m_gamepad) { + return; + } + mScriptContextGamepadDetach(&m_scriptContext, 0); +} + void ScriptingController::init() { mScriptContextInit(&m_scriptContext); mScriptContextAttachStdlib(&m_scriptContext); + mScriptContextAttachCanvas(&m_scriptContext); + mScriptContextAttachImage(&m_scriptContext); + mScriptContextAttachInput(&m_scriptContext); mScriptContextAttachSocket(&m_scriptContext); +#ifdef USE_JSON_C + mScriptContextAttachStorage(&m_scriptContext); +#endif mScriptContextRegisterEngines(&m_scriptContext); mScriptContextAttachLogger(&m_scriptContext, &m_logger); @@ -127,4 +348,135 @@ void ScriptingController::init() { if (m_engines.count() == 1) { m_activeEngine = *m_engines.begin(); } + +#ifdef USE_JSON_C + m_storageFlush.start(); +#endif +} + +uint32_t ScriptingController::qtToScriptingKey(const QKeyEvent* event) { + QString text(event->text()); + int key = event->key(); + + static const QHash keypadMap{ + {'0', mSCRIPT_KEY_KP_0}, + {'1', mSCRIPT_KEY_KP_1}, + {'2', mSCRIPT_KEY_KP_2}, + {'3', mSCRIPT_KEY_KP_3}, + {'4', mSCRIPT_KEY_KP_4}, + {'5', mSCRIPT_KEY_KP_5}, + {'6', mSCRIPT_KEY_KP_6}, + {'7', mSCRIPT_KEY_KP_7}, + {'8', mSCRIPT_KEY_KP_8}, + {'9', mSCRIPT_KEY_KP_9}, + {'+', mSCRIPT_KEY_KP_PLUS}, + {'-', mSCRIPT_KEY_KP_MINUS}, + {'*', mSCRIPT_KEY_KP_MULTIPLY}, + {'/', mSCRIPT_KEY_KP_DIVIDE}, + {',', mSCRIPT_KEY_KP_COMMA}, + {'.', mSCRIPT_KEY_KP_POINT}, + {Qt::Key_Enter, mSCRIPT_KEY_KP_ENTER}, + }; + static const QHash extraKeyMap{ + {Qt::Key_Escape, mSCRIPT_KEY_ESCAPE}, + {Qt::Key_Tab, mSCRIPT_KEY_TAB}, + {Qt::Key_Backtab, mSCRIPT_KEY_BACKSPACE}, + {Qt::Key_Backspace, mSCRIPT_KEY_BACKSPACE}, + {Qt::Key_Return, mSCRIPT_KEY_ENTER}, + {Qt::Key_Enter, mSCRIPT_KEY_ENTER}, + {Qt::Key_Insert, mSCRIPT_KEY_INSERT}, + {Qt::Key_Delete, mSCRIPT_KEY_DELETE}, + {Qt::Key_Pause, mSCRIPT_KEY_BREAK}, + {Qt::Key_Print, mSCRIPT_KEY_PRINT_SCREEN}, + {Qt::Key_SysReq, mSCRIPT_KEY_SYSRQ}, + {Qt::Key_Clear, mSCRIPT_KEY_CLEAR}, + {Qt::Key_Home, mSCRIPT_KEY_HOME}, + {Qt::Key_End, mSCRIPT_KEY_END}, + {Qt::Key_Left, mSCRIPT_KEY_LEFT}, + {Qt::Key_Up, mSCRIPT_KEY_UP}, + {Qt::Key_Right, mSCRIPT_KEY_RIGHT}, + {Qt::Key_Down, mSCRIPT_KEY_DOWN}, + {Qt::Key_PageUp, mSCRIPT_KEY_PAGE_UP}, + {Qt::Key_PageDown, mSCRIPT_KEY_DOWN}, + {Qt::Key_Shift, mSCRIPT_KEY_SHIFT}, + {Qt::Key_Control, mSCRIPT_KEY_CONTROL}, + {Qt::Key_Meta, mSCRIPT_KEY_SUPER}, + {Qt::Key_Alt, mSCRIPT_KEY_ALT}, + {Qt::Key_CapsLock, mSCRIPT_KEY_CAPS_LOCK}, + {Qt::Key_NumLock, mSCRIPT_KEY_NUM_LOCK}, + {Qt::Key_ScrollLock, mSCRIPT_KEY_SCROLL_LOCK}, + {Qt::Key_F1, mSCRIPT_KEY_F1}, + {Qt::Key_F2, mSCRIPT_KEY_F2}, + {Qt::Key_F3, mSCRIPT_KEY_F3}, + {Qt::Key_F4, mSCRIPT_KEY_F4}, + {Qt::Key_F5, mSCRIPT_KEY_F5}, + {Qt::Key_F6, mSCRIPT_KEY_F6}, + {Qt::Key_F7, mSCRIPT_KEY_F7}, + {Qt::Key_F8, mSCRIPT_KEY_F8}, + {Qt::Key_F9, mSCRIPT_KEY_F9}, + {Qt::Key_F10, mSCRIPT_KEY_F10}, + {Qt::Key_F11, mSCRIPT_KEY_F11}, + {Qt::Key_F12, mSCRIPT_KEY_F12}, + {Qt::Key_F13, mSCRIPT_KEY_F13}, + {Qt::Key_F14, mSCRIPT_KEY_F14}, + {Qt::Key_F15, mSCRIPT_KEY_F15}, + {Qt::Key_F16, mSCRIPT_KEY_F16}, + {Qt::Key_F17, mSCRIPT_KEY_F17}, + {Qt::Key_F18, mSCRIPT_KEY_F18}, + {Qt::Key_F19, mSCRIPT_KEY_F19}, + {Qt::Key_F20, mSCRIPT_KEY_F20}, + {Qt::Key_F21, mSCRIPT_KEY_F21}, + {Qt::Key_F22, mSCRIPT_KEY_F22}, + {Qt::Key_F23, mSCRIPT_KEY_F23}, + {Qt::Key_F24, mSCRIPT_KEY_F24}, + {Qt::Key_Menu, mSCRIPT_KEY_MENU}, + {Qt::Key_Super_L, mSCRIPT_KEY_SUPER}, + {Qt::Key_Super_R, mSCRIPT_KEY_SUPER}, + {Qt::Key_Help, mSCRIPT_KEY_HELP}, + {Qt::Key_Hyper_L, mSCRIPT_KEY_SUPER}, + {Qt::Key_Hyper_R, mSCRIPT_KEY_SUPER}, + }; + + if (event->modifiers() & Qt::KeypadModifier && keypadMap.contains(key)) { + return keypadMap[key]; + } + if (key >= 0 && key < 0x100) { + return key; + } + if (key < 0x01000000) { + if (text.isEmpty()) { + return 0; + } + QChar high = text[0]; + if (!high.isSurrogate()) { + return high.unicode(); + } + if (text.size() < 2) { + return 0; + } + return QChar::surrogateToUcs4(high, text[1]); + } + + if (extraKeyMap.contains(key)) { + return extraKeyMap[key]; + } + return 0; +} + + +uint16_t ScriptingController::qtToScriptingModifiers(Qt::KeyboardModifiers modifiers) { + uint16_t mod = 0; + if (modifiers & Qt::ShiftModifier) { + mod |= mSCRIPT_KMOD_SHIFT; + } + if (modifiers & Qt::ControlModifier) { + mod |= mSCRIPT_KMOD_CONTROL; + } + if (modifiers & Qt::AltModifier) { + mod |= mSCRIPT_KMOD_ALT; + } + if (modifiers & Qt::MetaModifier) { + mod |= mSCRIPT_KMOD_SUPER; + } + return mod; } diff --git a/src/platform/qt/scripting/ScriptingController.h b/src/platform/qt/scripting/ScriptingController.h index 03e40f7cf..a44e52b2e 100644 --- a/src/platform/qt/scripting/ScriptingController.h +++ b/src/platform/qt/scripting/ScriptingController.h @@ -7,19 +7,25 @@ #include #include +#include #include +#include #include #include "VFileDevice.h" #include +class QKeyEvent; class QTextDocument; +struct VideoBackend; + namespace QGBA { class CoreController; +class InputController; class ScriptingTextBuffer; class ScriptingTextBufferModel; @@ -31,10 +37,14 @@ public: ~ScriptingController(); void setController(std::shared_ptr controller); + void setInputController(InputController* controller); + void setVideoBackend(VideoBackend* backend); bool loadFile(const QString& path); bool load(VFileDevice& vf, const QString& name); + void event(QObject* obj, QEvent* ev); + mScriptContext* context() { return &m_scriptContext; } ScriptingTextBufferModel* textBufferModel() const { return m_bufferModel; } @@ -46,13 +56,27 @@ signals: public slots: void clearController(); + void updateVideoScale(); void reset(); void runCode(const QString& code); + void flushStorage(); + +protected: + bool eventFilter(QObject*, QEvent*) override; + +private slots: + void updateGamepad(); + void attach(); + private: void init(); - static mScriptTextBuffer* createTextBuffer(void* context); + void attachGamepad(); + void detachGamepad(); + + static uint32_t qtToScriptingKey(const QKeyEvent*); + static uint16_t qtToScriptingModifiers(Qt::KeyboardModifiers); struct Logger : mLogger { ScriptingController* p; @@ -64,7 +88,12 @@ private: QHash m_engines; ScriptingTextBufferModel* m_bufferModel; + mScriptGamepad m_gamepad; + std::shared_ptr m_controller; + InputController* m_inputController = nullptr; + + QTimer m_storageFlush; }; } diff --git a/src/platform/qt/scripting/ScriptingTextBuffer.cpp b/src/platform/qt/scripting/ScriptingTextBuffer.cpp index 7a4785d01..fe85eda0e 100644 --- a/src/platform/qt/scripting/ScriptingTextBuffer.cpp +++ b/src/platform/qt/scripting/ScriptingTextBuffer.cpp @@ -6,6 +6,7 @@ #include "ScriptingTextBuffer.h" #include "GBAApp.h" +#include "utils.h" #include #include @@ -205,13 +206,8 @@ void ScriptingTextBuffer::setSize(struct mScriptTextBuffer* buffer, uint32_t col void ScriptingTextBuffer::moveCursor(struct mScriptTextBuffer* buffer, uint32_t x, uint32_t y) { ScriptingTextBuffer* self = static_cast(buffer)->p; - if (x > INT_MAX) { - x = INT_MAX; - } - if (y > INT_MAX) { - y = INT_MAX; - } - QMetaObject::invokeMethod(self, "moveCursor", Q_ARG(QPoint, QPoint(x, y))); + QPoint point(saturateCast(x), saturateCast(y)); + QMetaObject::invokeMethod(self, "moveCursor", Q_ARG(QPoint, point)); } void ScriptingTextBuffer::advance(struct mScriptTextBuffer* buffer, int32_t adv) { diff --git a/src/platform/qt/ts/mgba-de.ts b/src/platform/qt/ts/mgba-de.ts index 7bc27a274..a1d1b2e15 100644 --- a/src/platform/qt/ts/mgba-de.ts +++ b/src/platform/qt/ts/mgba-de.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + Game Boy Advance-ROMs (%1) + + + + Game Boy ROMs (%1) + Game Boy-ROMs (%1) + + + + All ROMs (%1) + Alle ROMs (%1) + + + + %1 Video Logs (*.mvl) + %1 Video-Logs (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Download-Größe: %3 QGBA::ApplicationUpdater - + Stable Stabil - + Development Entwicklung - + Unknown Unbekannt - + (None) (keiner) @@ -364,48 +387,48 @@ Download-Größe: %3 QGBA::CoreController - + Reset r%1-%2 %3 r%1-%2 %3 zurücksetzen - - + + Rewinding not currently enabled Rücklauf ist derzeit nicht aktiviert - + Reset the game? Spiel zurücksetzen? - + Most games will require a reset to load the new save. Do you want to reset now? Die meisten Spiele müssen zurückgesetzt werden, um einen neuen Spielstand zu laden. Möchtest Du das Spiel jetzt zurücksetzen? - + Failed to open save file: %1 Fehler beim Öffnen der Speicherdatei: %1 - + Failed to open game file: %1 Fehler beim Öffnen der Spieldatei: %1 - + Can't yank pack in unexpected platform! Das GamePak kann nur auf unterstützten Plattformen herausgezogen werden! - + Failed to open snapshot file for reading: %1 Konnte Snapshot-Datei %1 nicht zum Lesen öffnen - + Failed to open snapshot file for writing: %1 Konnte Snapshot-Datei %1 nicht zum Schreiben öffnen @@ -413,17 +436,17 @@ Download-Größe: %3 QGBA::CoreManager - + Failed to open game file: %1 Fehler beim Öffnen der Spieldatei: %1 - + Could not load game. Are you sure it's in the correct format? Konnte das Spiel nicht laden. Bist Du sicher, dass es im korrekten Format vorliegt? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). Fehler beim Laden der Spielstand-Datei; Speicherdaten können nicht aktualisiert werden. Bitte stelle sicher, dass das Speicherdaten-Verzeichnis ohne zusätzliche Berechtigungen (z.B. UAC in Windows) beschreibbar ist. @@ -449,7 +472,7 @@ Download-Größe: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing CLI-Verlauf kann nicht gespeichert werden @@ -502,6 +525,200 @@ Download-Größe: %3 Verbindung zu Dolphin konnte nicht hergestellt werden. + + QGBA::ForwarderGenerator + + + 3DS + 3DS + + + + Vita + Vita + + + + QGBA::ForwarderGenerator3DS + + + Icon + Icon + + + + Banner + Banner + + + + QGBA::ForwarderGeneratorVita + + + Bubble + Blase + + + + Background + Hintergrund + + + + Startup + Start + + + + QGBA::ForwarderView + + + Create forwarder + Forwarder erstellen + + + + Files + Dateien + + + + ROM file: + ROM-Datei: + + + + + + Browse + Durchsuchen + + + + Output filename: + Ausgabe-Dateiname: + + + + Forwarder base: + Forwarder-Basis: + + + + Latest stable version + Letzte stabile Version + + + + Latest development build + Letzte Entwicklungs-Version + + + + Specific file + Spezifische Datei + + + + Base file: + Basis-Datei: + + + + System + System + + + + 3DS + 3DS + + + + Vita + Vita + + + + Presentation + Präsentation + + + + Title: + Titel: + + + + Images: + Bilder: + + + + Use default image + Verwende Standard-Bild + + + + Preferred size: + Bevorzugte Größe: + + + + Select image file + Bild-Datei auswählen + + + + Select ROM file + ROM-Datei auswählen + + + + Select output filename + Ausgabe-Dateiname auswählen + + + + Select base file + Basis-Datei auswählen + + + + Build finished + Erzeugung erfolgreich + + + + Forwarder finished building + Der Forwarder wurde erfolgreich erstellt + + + + Build failed + Erzeugung fehlgeschlagen + + + + Failed to build forwarder + Der Forwarder konnte nicht erzeugt werden + + + + %1 installable package (*.%2) + Installierbares %1-Paket (*.%2) + + + + Select an image + Bild auswählen + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Download-Größe: %3 Zurücksetzen - + Export frame Bild exportieren - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Keine - + Background Hintergrund - + Window Fenster - + Objwin Objwin - + Sprite Sprite - + Backdrop Hintergrund - + Frame Frame - + %1 %2 %1 %2 @@ -593,7 +810,7 @@ Download-Größe: %3 QGBA::GBAApp - + Enable Discord Rich Presence Discord-Integration aktivieren @@ -601,22 +818,22 @@ Download-Größe: %3 QGBA::GBAKeyEditor - + Clear Button Button löschen - + Clear Analog Analog löschen - + Refresh Aktualisieren - + Set all Alle belegen @@ -750,148 +967,168 @@ Download-Größe: %3 QGBA::GameBoy - - + + Autodetect Automatisch erkennen - + Game Boy (DMG) Game Boy (DMG) - + Game Boy Pocket (MGB) Game Boy Pocket (MGB) - + Super Game Boy (SGB) Super Game Boy (SGB) - + Super Game Boy 2 (SGB) Super Game Boy 2 (SGB) - + Game Boy Color (CGB) Game Boy Color (CGB) - + Game Boy Advance (AGB) Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) Super Game Boy Color (SGB + CGB) - + ROM Only Nur ROM - + MBC1 MBC1 - + MBC2 MBC2 - + MBC3 MBC3 - + MBC3 + RTC MBC3 + RTC - + MBC5 MBC5 - + MBC5 + Rumble MBC5 + Rumble - + MBC6 MBC6 - + MBC7 (Tilt) MBC7 (Tilt) - + MMM01 MMM01 - + HuC-1 HuC-1 - + HuC-3 HuC-3 - + Pocket Cam Pocket Cam - + TAMA5 TAMA5 - + Wisdom Tree Wisdom Tree - + + NT (old 1) + NT (alt 1) + + + + NT (old 2) + NT (alt 2) + + + NT (new) NT (neu) - + Pokémon Jade/Diamond Pokémon Jade/Diamond - + BBD BBD - + Hitek Hitek - + + GGB-81 + GGB-81 + + + + Li Cheng + Li Cheng + + + Sachen (MMC1) Sachen (MMC1) - + Sachen (MMC2) Sachen (MMC2) @@ -2769,26 +3006,11 @@ Download-Größe: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - Menü - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Download-Größe: %3 Defekt - + Slot %1 Speicherplatz %1 @@ -3136,39 +3358,39 @@ Download-Größe: %3 Spiegel - + None Keiner - + Both Beidseitig - + Horizontal Horizontal - + Vertical Vertikal - - - + + + N/A Nicht verfügbar - + Export map Map exportieren - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3419,22 +3641,22 @@ Download-Größe: %3 Aktualisieren - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 byte%2 @@ -3525,6 +3747,24 @@ Download-Größe: %3 Frame %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4023,6 +4263,7 @@ Download-Größe: %3 + (unknown) (unbekannt) @@ -4066,6 +4307,11 @@ Download-Größe: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4087,7 +4333,7 @@ Download-Größe: %3 <html><head/><body><p>To file a bug report, please first generate a report file to attach to the bug report you're about to file. It is recommended that you include the save files, as these often help with debugging issues. This will collect some information about the version of {projectName} you're running, your configuration, your computer, and the game you currently have open (if any). Once this collection is completed you can review all of the information gathered below and save it to a zip file. The collection will automatically attempt to redact any personal information, such as your username if it's in any of the paths gathered, but just in case you can edit it afterwards. After you have generated and saved it, please click the button below or go to <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> to file the bug report on GitHub. Make sure to attach the report you generated!</p></body></html> - <html><head/><body><p>Um einen Fehler zu melden, erstelle bitte zuerst eine berichtsdatei, welche Du an deinen Fehlerbericht anhängen kannst. Es wird empfohlen, dass du in dem Archiv auch eine Spielstand-Datei beilegst, da diese häufig bei der Fehlersuche behilflich ist. Der Fehlerbericht wird einige Informationen über die verwendete Version von {projectName}, dein System, deinen Computer und das derzeit geöffnete Spiel. Sobald die Sammlung vollständig ist, kannst du alle gesammelten Informationen einsehen und in eine ZIP-Datei speichern. Wir versuchen automatisch, so viele persönlichen Daten wie möglich zu entfernen. Nachdem du den Bericht erstellt und abgespeichert hast, klicke bitte auf den untenstehenden Button oder besuche <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> um einen Fehlerbericht auf GitHub zu erzeugen. </p></body></html> + <html><head/><body><p>Um einen Fehler zu melden, erstelle bitte zuerst eine Berichtsdatei, welche Du an deinen Fehlerbericht anhängen kannst. Es wird empfohlen, dass du in dem Archiv auch eine Spielstand-Datei beilegst, da diese häufig bei der Fehlersuche behilflich ist. Der Fehlerbericht wird einige Informationen über die verwendete Version von {projectName}, dein System, deinen Computer und das derzeit geöffnete Spiel. Sobald die Sammlung vollständig ist, kannst du alle gesammelten Informationen einsehen und in eine ZIP-Datei speichern. Wir versuchen automatisch, so viele persönlichen Daten wie möglich zu entfernen. Nachdem du den Bericht erstellt und abgespeichert hast, klicke bitte auf den untenstehenden Button oder besuche <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> um einen Fehlerbericht auf GitHub zu erzeugen. </p></body></html> @@ -4173,7 +4419,7 @@ Download-Größe: %3 Keine gültigen Konvertierungen gefunden - + Cannot convert save games between platforms Der Spielstand konnte nicht zwischen verschiedenen Plattformen konvertiert werden @@ -4199,92 +4445,97 @@ Download-Größe: %3 Ausgabedatei - + %1 %2 save game Spielstand %1 %2 - + little endian little-endian - + big endian big-endian - + SRAM SRAM - + %1 flash %1 Flash - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 MBC2, komprimiert - + unpacked MBC2 MBC2, entpackt - + MBC6 flash MBC6 Flash-Speicher - + MBC6 combined SRAM + flash MBC6 SRAM + Flash-Speicher - + MBC6 SRAM MBC6 SRAM - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game Savestate %1 mit eingebettetem Spielstand %2 - + %1 SharkPort %2 save game SharkPort %1 Spielstand %2 - + %1 GameShark Advance SP %2 save game %1 GameShark Advance SP %2 Spielstand @@ -4292,7 +4543,7 @@ Download-Größe: %3 QGBA::ScriptingTextBuffer - + Untitled buffer Unbenannter Puffer @@ -4438,95 +4689,105 @@ Download-Größe: %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimedia - + SDL SDL - + Software (Qt) Software (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (erzwinge Version 1.x) - + None Keiner - + None (Still Image) Keiner (Standbild) - + Keyboard Tastatur - + Controllers Gamepads - + Shortcuts Tastenkürzel - - + + Shaders Shader - + Select BIOS BIOS auswählen - + Select directory Verzeichnis auswählen - + + Select image + Bild auswählen + + + + Image file (*.png *.jpg *.jpeg) + Bilddatei (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never Nie - + Just now Gerade eben - + Less than an hour ago Vor weniger als einer Stunde - + %n hour(s) ago Vor %n Stunde @@ -4534,7 +4795,7 @@ Download-Größe: %3 - + %n day(s) ago Vor %n Tag @@ -4728,7 +4989,7 @@ Download-Größe: %3 - + frames Bild(er) @@ -4811,77 +5072,87 @@ Download-Größe: %3 Wenn minimiert: - + + Custom border: + + + + Current channel: Aktueller Channel: - + Current version: Aktuelle Version: - + Update channel: Update-Channel: - + Available version: Verfügbare Version: - + (Unknown) (unbekannt) - + Last checked: Zuletzt geprüft: - + Automatically check on start Beim Start automatisch auf Aktualisierungen prüfen - + Check now Jetzt überprüfen - + + Rewind speed: + + + + Default color palette only Nur Standard-Farbpalette - + SGB color palette if available SGB-Farbpalette, sofern verfügbar - + GBC color palette if available GBC-Farbpalette, sofern verfügbar - + SGB (preferred) or GBC color palette if available SGB (bevorzugt) oder GBC-Farbpalette, sofern verfügbar - + Game Boy Camera Game Boy Camera - + Driver: Treiber: - + Source: Quelle: @@ -4952,47 +5223,47 @@ Download-Größe: %3 Zusätzliche Savestate-Daten laden: - + Models Modelle - + GB only: Nur GB: - + SGB compatible: SGB-kompatibel: - + GBC only: Nur GBC: - + GBC compatible: GBC-kompatibel: - + SGB and GBC compatible: SGB- und GBC-kompatibel: - + Game Boy palette Game Boy-Palette - + Preset: Voreinstellungen: - + Enable Game Boy Player features by default Game Boy Player-Features standardmäßig aktivieren @@ -5012,77 +5283,77 @@ Download-Größe: %3 Dateinamen statt ROM-Namen in der Titelleiste anzeigen - + Fast forward (held) speed: Vorlauf-Geschwindigkeit (halten): - + Enable VBA bug compatibility in ROM hacks VBA-Bug-Kompatibilität in ROM-Hacks aktivieren - + Video renderer: Video-Renderer: - + Software Software - + OpenGL enhancements OpenGL-Verbesserungen - + High-resolution scale: Hochauflösende Skalierung: - + XQ GBA audio (experimental) XQ GBA-Audio (experimentell) - + Cheats Cheats - + Log to file In Datei protokollieren - + Log to console Auf die Konsole protokollieren - + Select Log File Protokoll-Datei auswählen - + Default BG colors: Standard-Hintergrundfarben: - + Default sprite colors 1: Standard-Sprite-Farben 1: - + Default sprite colors 2: Standard-Sprite-Farben 2: - + Super Game Boy borders Super Game Boy-Rahmen @@ -5102,41 +5373,42 @@ Download-Größe: %3 Cache leeren - + Fast forward speed: Vorlauf-Geschwindigkeit: - + Preload entire ROM into memory ROM-Datei vollständig in Arbeitsspeicher vorladen - - - - - - - - - + + + + + + + + + + Browse Durchsuchen - + Use BIOS file if found BIOS-Datei verwenden, wenn vorhanden - + Skip BIOS intro BIOS-Intro überspringen - - + + Unbounded unbegrenzt @@ -5151,17 +5423,17 @@ Download-Größe: %3 BIOS - + Run all Alle ausführen - + Remove known Bekannte entfernen - + Detect and remove Erkennen und entfernen @@ -5183,7 +5455,7 @@ Download-Größe: %3 Cheat-Codes - + Enable rewind Rücklauf aktivieren @@ -5193,71 +5465,71 @@ Download-Größe: %3 Bilineare Filterung - + Rewind history: Rücklauf-Verlauf: - + Idle loops: Leerlaufprozesse: - + Autofire interval: Autofeuer-Intervall: - + (240×160) (240×160) - + GB BIOS file: Datei mit GB-BIOS: - + GBA BIOS file: Datei mit GBA-BIOS: - + GBC BIOS file: Datei mit GBC-BIOS: - + SGB BIOS file: Datei mit SGB-BIOS: - + Save games Spielstände - - - - - + + + + + Same directory as the ROM Verzeichnis der ROM-Datei - + Save states Savestates - + Screenshots Bildschirmfotos - + Patches Korrekturen @@ -5270,27 +5542,28 @@ Download-Größe: %3 Kein Shader aktiv - + + Load shader Shader laden - + No shader loaded Kein Shader geladen - + by %1 von %1 - + Preprocessing Vorbehandlung - + Pass %1 Durchlauf %1 @@ -5333,17 +5606,17 @@ Download-Größe: %3 QGBA::ShortcutModel - + Action Aktion - + Keyboard Tastatur - + Gamepad Gamepad @@ -5463,17 +5736,17 @@ Download-Größe: %3 QGBA::VideoView - + Failed to open output video file: %1 Fehler beim Öffnen der Ausgabe-Videodatei: %1 - + Native (%0x%1) Nativ (%0x%1) - + Select output file Ausgabedatei auswählen @@ -5608,7 +5881,7 @@ Download-Größe: %3 WavPack - + WavPack @@ -5684,105 +5957,85 @@ Download-Größe: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - Game Boy Advance-ROMs (%1) - - - - Game Boy ROMs (%1) - Game Boy-ROMs (%1) - - - - All ROMs (%1) - Alle ROMs (%1) - - - - %1 Video Logs (*.mvl) - %1 Video-Logs (*.mvl) - - - + Archives (%1) Archive (%1) - - - + + + Select ROM ROM auswählen - - + + Select save Speicherdatei wählen - + Select patch Patch wählen - + Patches (*.ips *.ups *.bps) Korrekturen (*.ips *.ups *.bps) - + Select e-Reader card images Bilder der Lesegerät-Karte auswählen - + Image file (*.png *.jpg *.jpeg) Bilddatei (*.png *.jpg *.jpeg) - + Conversion finished Konvertierung abgeschlossen - + %1 of %2 e-Reader cards converted successfully. %1 von %2 Lesegerät-Karten erfolgreich konvertiert. - + Select image Bild auswählen - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Bild-Datei (*.png *.gif *.jpg *.jpeg);;Alle Dateien (*) - + GameShark saves (*.sps *.xps) GameShark-Speicherdaten (*.sps *.xps) - + Select video log Video-Log auswählen - + Video logs (*.mvl) Video-Logs (*.mvl) - + Crash Absturz - + The game has crashed with the following error: %1 @@ -5791,679 +6044,694 @@ Download-Größe: %3 %1 - + Unimplemented BIOS call Nicht implementierter BIOS-Aufruf - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Dieses Spiel verwendet einen BIOS-Aufruf, der nicht implementiert ist. Bitte verwenden Sie für die beste Spielerfahrung das offizielle BIOS. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Es konnte kein geeignetes Ausgabegerät erstellt werden, stattdessen wird Software-Rendering als Rückfalloption genutzt. Spiele laufen möglicherweise langsamer, besonders innerhalb großer Fenster. - + Really make portable? Portablen Modus wirklich aktivieren? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? Diese Einstellung wird den Emulator so konfigurieren, dass er seine Konfiguration aus dem gleichen Verzeichnis wie die Programmdatei lädt. Möchten Sie fortfahren? - + Restart needed Neustart benötigt - + Some changes will not take effect until the emulator is restarted. Einige Änderungen werden erst übernommen, wenn der Emulator neu gestartet wurde. - + - Player %1 of %2 - Spieler %1 von %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 Bilder/Sekunde) - %4 - + &File &Datei - + Load &ROM... &ROM laden... - + Load ROM in archive... ROM aus Archiv laden... - + Save games Spielstände - + Automatically determine Automatisch erkennen - + Use player %0 save game Verwende Spielstand von Spieler %0 - + Load &patch... &Patch laden... - + Boot BIOS BIOS booten - + Replace ROM... ROM ersetzen... - + Convert e-Reader card image to raw... Lesegerät-Kartenbild in Rohdaten umwandeln … - + ROM &info... ROM-&Informationen... - + Recent Zuletzt verwendet - + Make portable Portablen Modus aktivieren - + &Load state Savestate (aktueller Zustand) &laden - + Load state file... Savestate-Datei laden... - + &Save state Savestate (aktueller Zustand) &speichern - + Save state file... Savestate-Datei speichern... - + Quick load Schnell laden - + Quick save Schnell speichern - + Load recent Lade zuletzt gespeicherten Savestate - + Save recent Speichere aktuellen Zustand - + Undo load state Laden des Savestate rückgängig machen - + Undo save state Speichern des Savestate rückgängig machen - - + + State &%1 Savestate &%1 - + Load camera image... Lade Kamerabild... - + Convert save game... Spielstand konvertieren... - + Reset needed Zurücksetzen erforderlich - + Some changes will not take effect until the game is reset. Einige Änderungen werden erst dann wirksam, wenn das Spiel zurückgesetzt wird. - + New multiplayer window Neues Multiplayer-Fenster - + Connect to Dolphin... Mit Dolphin verbinden... - + Report bug... Fehler melden... - + E&xit &Beenden - + &Emulation &Emulation - + &Reset Zu&rücksetzen - + Sh&utdown Schli&eßen - + Yank game pak Spielmodul herausziehen - + &Pause &Pause - + &Next frame &Nächstes Bild - + Fast forward (held) Schneller Vorlauf (gehalten) - + &Fast forward Schneller &Vorlauf - + Fast forward speed Vorlauf-Geschwindigkeit - + Unbounded Unbegrenzt - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Zurückspulen (gehalten) - + Re&wind Zur&ückspulen - + Step backwards Schrittweiser Rücklauf - + Solar sensor Sonnen-Sensor - + Increase solar level Sonnen-Level erhöhen - + Decrease solar level Sonnen-Level verringern - + Brightest solar level Hellster Sonnen-Level - + Darkest solar level Dunkelster Sonnen-Level - + Brightness %1 Helligkeit %1 - + BattleChip Gate... BattleChip Gate... - + Audio/&Video Audio/&Video - + Frame size Bildgröße - + Toggle fullscreen Vollbildmodus umschalten - + Lock aspect ratio Seitenverhältnis korrigieren - + Force integer scaling Pixelgenaue Skalierung (Integer scaling) - + Interframe blending Interframe-Überblendung - + Frame&skip Frame&skip - + Mute Stummschalten - + FPS target Bildwiederholrate - + Take &screenshot &Screenshot erstellen - + F12 F12 - + Scripting... Scripting... - + + Create forwarder... + Forwarder erzeugen... + + + Game state views Spiel-Zustände ansehen - + Clear Leeren - + Game Boy Printer... Game Boy Printer... - + Video layers Video-Ebenen - + Audio channels Audio-Kanäle - + Adjust layer placement... Lage der Bildebenen anpassen... - + &Tools &Werkzeuge - + View &logs... &Logs ansehen... - + Game &overrides... Spiel-&Überschreibungen... - + &Cheats... &Cheats... - + Open debugger console... Debugger-Konsole öffnen... - + Start &GDB server... &GDB-Server starten... - + Settings... Einstellungen... - + Select folder Ordner auswählen - + Save games (%1) Spielstände (%1) - + Select save game Spielstand auswählen - + mGBA save state files (%1) mGBA-Savestates (%1) - - + + Select save state Savestate auswählen - + Select e-Reader dotcode e-Reader-Code auswählen - + e-Reader card (*.raw *.bin *.bmp) e-Reader-Karte (*.raw *.bin *.bmp) - + GameShark saves (*.gsv *.sps *.xps) GameShark-Spielstände (*.gsv *.sps *.xps) - + Couldn't Start Konnte nicht gestartet werden - + Could not start game. Spiel konnte nicht gestartet werden. - + Add folder to library... Ordner zur Bibliothek hinzufügen... - + Load alternate save game... Alternativen Spielstand laden... - + Load temporary save game... Temporären Spielstand laden... - + Scan e-Reader dotcodes... e-Reader-Code einlesen... - + Import GameShark Save... GameShare-Speicherstand importieren... - + Export GameShark Save... GameShark-Speicherstand exportieren... - + About... Über... - + %1× %1x - + Bilinear filtering Bilineare Filterung - + Native (59.7275) Nativ (59.7275) - + Record A/V... Audio/Video aufzeichnen... - + Record GIF/WebP/APNG... GIF/WebP/APNG aufzeichnen... - + Game Pak sensors... Spielmodul-Sensoren... - + View &palette... &Palette betrachten... - + View &sprites... &Sprites betrachten... - + View &tiles... &Tiles betrachten... - + View &map... &Map betrachten... - + &Frame inspector... &Bildbetrachter... - + View memory... Speicher betrachten... - + Search memory... Speicher durchsuchen... - + View &I/O registers... &I/O-Register betrachten... - + Record debug video log... Video-Protokoll aufzeichnen... - + Stop debug video log Aufzeichnen des Video-Protokolls beenden - + Exit fullscreen Vollbildmodus beenden - + GameShark Button (held) GameShark-Taste (gehalten) - + Autofire Autofeuer - + Autofire A Autofeuer A - + Autofire B Autofeuer B - + Autofire L Autofeuer L - + Autofire R Autofeuer R - + Autofire Start Autofeuer Start - + Autofire Select Autofeuer Select - + Autofire Up Autofeuer nach oben - + Autofire Right Autofeuer rechts - + Autofire Down Autofeuer nach unten - + Autofire Left Autofeuer links @@ -6471,55 +6739,70 @@ Download-Größe: %3 QObject - + %1 byte %1 Byte - + %1 kiB %1 KiB - + %1 MiB %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + Menü + QShortcut - + Shift Shift - + Control Strg - + Alt Alt - + Meta AltGr diff --git a/src/platform/qt/ts/mgba-en.ts b/src/platform/qt/ts/mgba-en.ts index ec361c5dc..4b67efd50 100644 --- a/src/platform/qt/ts/mgba-en.ts +++ b/src/platform/qt/ts/mgba-en.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + + + + + Game Boy ROMs (%1) + + + + + All ROMs (%1) + + + + + %1 Video Logs (*.mvl) + + + QGBA::AboutScreen @@ -86,22 +109,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable - + Development - + Unknown - + (None) @@ -358,48 +381,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 - + Failed to open game file: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 - + Failed to open snapshot file for writing: %1 @@ -407,17 +430,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 - + Could not load game. Are you sure it's in the correct format? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -443,7 +466,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -496,6 +519,200 @@ Download size: %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -534,52 +751,52 @@ Download size: %3 - + Export frame - + Portable Network Graphics (*.png) - + None - + Background - + Window - + Objwin - + Sprite - + Backdrop - + Frame - + %1 %2 @@ -587,7 +804,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence @@ -595,22 +812,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button - + Clear Analog - + Refresh - + Set all @@ -744,148 +961,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2763,26 +3000,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- - - - Super (L) - - - - - Super (R) - - - - - Menu - - QGBA::LibraryTree @@ -2904,7 +3126,7 @@ Download size: %3 - + Slot %1 @@ -3130,39 +3352,39 @@ Download size: %3 - + None - + Both - + Horizontal - + Vertical - - - + + + N/A - + Export map - + Portable Network Graphics (*.png) @@ -3413,22 +3635,22 @@ Download size: %3 - + (%0/%1×) - + (⅟%0×) - + (%0×) - + %1 byte%2 @@ -3519,6 +3741,24 @@ Download size: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4017,6 +4257,7 @@ Download size: %3 + (unknown) @@ -4060,6 +4301,11 @@ Download size: %3 CRC32: + + + Save file: + + QGBA::ReportView @@ -4167,7 +4413,7 @@ Download size: %3 - + Cannot convert save games between platforms @@ -4193,92 +4439,97 @@ Download size: %3 - + %1 %2 save game - + little endian - + big endian - + SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4286,7 +4537,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4432,95 +4683,105 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia - + SDL - + Software (Qt) - - + + OpenGL - + OpenGL (force version 1.x) - + None - + None (Still Image) - + Keyboard - + Controllers - + Shortcuts - - + + Shaders - + Select BIOS - + Select directory - - (%1×%2) + + Select image - - Never + + Image file (*.png *.jpg *.jpeg) + (%1×%2) + + + + + Never + + + + Just now - + Less than an hour ago - + %n hour(s) ago @@ -4528,7 +4789,7 @@ Download size: %3 - + %n day(s) ago @@ -4727,7 +4988,7 @@ Download size: %3 - + frames @@ -4815,77 +5076,77 @@ Download size: %3 - + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now - + Default color palette only - + SGB color palette if available - + GBC color palette if available - + SGB (preferred) or GBC color palette if available - + Game Boy Camera - + Driver: - + Source: @@ -4980,58 +5241,68 @@ Download size: %3 - + + Custom border: + + + + Fast forward speed: - - + + Unbounded - + Fast forward (held) speed: - + Autofire interval: - + Enable rewind - + Rewind history: - + + Rewind speed: + + + + Idle loops: - + Run all - + Remove known - + Detect and remove - + Preload entire ROM into memory @@ -5052,42 +5323,42 @@ Download size: %3 - + Models - + GB only: - + SGB compatible: - + GBC only: - + GBC compatible: - + SGB and GBC compatible: - + Game Boy palette - + Preset: @@ -5104,154 +5375,155 @@ Download size: %3 - + Enable Game Boy Player features by default - + Enable VBA bug compatibility in ROM hacks - + Video renderer: - + Software - + OpenGL enhancements - + High-resolution scale: - + (240×160) - + XQ GBA audio (experimental) - + GB BIOS file: - - - - - - - - - + + + + + + + + + + Browse - + Use BIOS file if found - + Skip BIOS intro - + GBA BIOS file: - + GBC BIOS file: - + SGB BIOS file: - + Save games - - - - - + + + + + Same directory as the ROM - + Save states - + Screenshots - + Patches - + Cheats - + Log to file - + Log to console - + Select Log File - + Default BG colors: - + Default sprite colors 1: - + Default sprite colors 2: - + Super Game Boy borders @@ -5264,27 +5536,28 @@ Download size: %3 - + + Load shader - + No shader loaded - + by %1 - + Preprocessing - + Pass %1 @@ -5327,17 +5600,17 @@ Download size: %3 QGBA::ShortcutModel - + Action - + Keyboard - + Gamepad @@ -5457,17 +5730,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file @@ -5678,784 +5951,779 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - - - - - Game Boy ROMs (%1) - - - - - All ROMs (%1) - - - - - %1 Video Logs (*.mvl) - - - - + Archives (%1) - - - + + + Select ROM - + Select folder - - + + Select save - + Select patch - + Patches (*.ips *.ups *.bps) - + Select e-Reader dotcode - + e-Reader card (*.raw *.bin *.bmp) - + Select image - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) - + GameShark saves (*.sps *.xps) - + Select video log - + Video logs (*.mvl) - + Crash - + The game has crashed with the following error: %1 - + Couldn't Start - + Could not start game. - + Unimplemented BIOS call - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. - + Really make portable? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - + Restart needed - + Some changes will not take effect until the emulator is restarted. - + - Player %1 of %2 - + %1 - %2 - + %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File - + Load &ROM... - + Load ROM in archive... - + Add folder to library... - + Save games (%1) - + Select save game - + mGBA save state files (%1) - - + + Select save state - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Load alternate save game... - + Load temporary save game... - + Load &patch... - + Boot BIOS - + Replace ROM... - + Scan e-Reader dotcodes... - + Convert e-Reader card image to raw... - + ROM &info... - + Recent - + Make portable - + &Load state - + Load state file... - + &Save state - + Save state file... - + Quick load - + Quick save - + Load recent - + Save recent - + Undo load state - + Undo save state - - + + State &%1 - + Load camera image... - + Convert save game... - + GameShark saves (*.gsv *.sps *.xps) - + Reset needed - + Some changes will not take effect until the game is reset. - + Save games - + Import GameShark Save... - + Export GameShark Save... - + Automatically determine - + Use player %0 save game - + New multiplayer window - + Connect to Dolphin... - + Report bug... - + About... - + E&xit - + &Emulation - + &Reset - + Sh&utdown - + Yank game pak - + &Pause - + &Next frame - + Fast forward (held) - + &Fast forward - + Fast forward speed - + Unbounded - + %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) - + Re&wind - + Step backwards - + Solar sensor - + Increase solar level - + Decrease solar level - + Brightest solar level - + Darkest solar level - + Brightness %1 - + Game Boy Printer... - + BattleChip Gate... - + Audio/&Video - + Frame size - + %1× - + Toggle fullscreen - + Lock aspect ratio - + Force integer scaling - + Interframe blending - + Bilinear filtering - + Frame&skip - + Mute - + FPS target - + Native (59.7275) - + Take &screenshot - + F12 - + Record A/V... - + Record GIF/WebP/APNG... - + Video layers - + Audio channels - + Adjust layer placement... - + &Tools - + View &logs... - + Game &overrides... - + Game Pak sensors... - + &Cheats... - + + Create forwarder... + + + + Settings... - + Open debugger console... - + Start &GDB server... - + Scripting... - + Game state views - + View &palette... - + View &sprites... - + View &tiles... - + View &map... - + &Frame inspector... - + View memory... - + Search memory... - + View &I/O registers... - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear @@ -6463,55 +6731,70 @@ Download size: %3 QObject - + %1 byte - + %1 kiB - + %1 MiB - + GBA - + GB - + ? + + + Super (L) + + + + + Super (R) + + + + + Menu + + QShortcut - + Shift - + Control - + Alt - + Meta diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index 8cf07904c..83c4d5d98 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ROMs para Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROMs para Game Boy Advance (%1) + + + + All ROMs (%1) + Todas las ROMs (%1) + + + + %1 Video Logs (*.mvl) + %1 Registros de vídeo (*.mvl) + + QGBA::AboutScreen @@ -21,7 +44,7 @@ {projectName} would like to thank the following patrons from Patreon: - {projectName} desea agradecer a los siguientes patrocinadores desde Patreon: + {projectName} desea agradecer a los siguientes patrocinadores de Patreon: @@ -55,14 +78,14 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Do you want to download and install it now? You will need to restart the emulator when the download is complete. -¿Quieres descargarlo e instalarlo ahora? Deberá reiniciar el emulador cuando se complete la descarga. +¿Quieres descargarlo e instalarlo ahora? Deberás reiniciar el emulador cuando se complete la descarga. Auto-update is not available on this platform. If you wish to update you will need to do it manually. -La actualización automática no está disponible en esta plataforma. Si desea actualizar, deberá hacerlo manualmente. +La actualización automática no está disponible en esta plataforma. Si deseas actualizar, deberás hacerlo manualmente. @@ -71,7 +94,7 @@ New version: %2 Download size: %3 Versión actual: %1 Nueva versión: %2 -Tamaño de la descarga: %3 +Tamaño de descarga: %3 @@ -92,22 +115,22 @@ Tamaño de la descarga: %3 QGBA::ApplicationUpdater - + Stable Estable - + Development Desarrollo - + Unknown - Desconocido + Desconocido - + (None) (Ninguno) @@ -117,7 +140,7 @@ Tamaño de la descarga: %3 Open in archive... - Abrir desde contenedor... + Abrir desde archivo comprimido... @@ -130,12 +153,12 @@ Tamaño de la descarga: %3 Tile # - Tile Nº + Tesela nº Palette # - Paleta Nº + Paleta nº @@ -170,12 +193,12 @@ Tamaño de la descarga: %3 Can't set format of context-less audio device - + No se puede establecer el formato de un dispositivo de audio sin contexto Audio device is missing its core - + No se encuentra el sistema del dispositivo de audio @@ -188,7 +211,7 @@ Tamaño de la descarga: %3 Can't start an audio processor without input - Sin entrada no se puede iniciar un procesador de audio + No se puede iniciar el procesador de audio sin entrada @@ -196,7 +219,7 @@ Tamaño de la descarga: %3 Can't start an audio processor without input - Sin entrada no se puede iniciar un procesador de audio + No se puede iniciar el procesador de audio sin entrada @@ -229,7 +252,7 @@ Tamaño de la descarga: %3 Add - Agregar + Añadir @@ -259,7 +282,7 @@ Tamaño de la descarga: %3 Show advanced - Mostrar ajustes avanzados + Mostrar configuración avanzada @@ -269,23 +292,23 @@ Tamaño de la descarga: %3 BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? - Faltan los datos de BattleChip. BattleChip Gates seguirán funcionando, pero faltarán algunos gráficos. ¿Quiere descargar los datos ahora? + Faltan los datos de BattleChip. Los BattleChip Gates seguirán funcionando pero faltarán algunos gráficos. ¿Quieres descargar los datos ahora? Select deck file - + Seleccionar fichero de baraja Incompatible deck - + Baraja no compatible The selected deck is not compatible with this Chip Gate - + La baraja seleccionada no es compatible con este Chip Gate @@ -358,54 +381,54 @@ Tamaño de la descarga: %3 Some cheats could not be added. Please ensure they're formatted correctly and/or try other cheat types. - Algunos trucos no se pudieron añadir. Asegúrese de que están en el formato correcto y/o pruebe otro tipo de trucos. + Algunos trucos no se pudieron añadir. Asegúrate de que están en el formato correcto y/o prueba otro tipo de trucos. QGBA::CoreController - + Reset r%1-%2 %3 Reiniciar r%1-%2 %3 - - + + Rewinding not currently enabled Rebobinado desactivado actualmente - + Reset the game? ¿Reiniciar el juego? - + Most games will require a reset to load the new save. Do you want to reset now? La mayoría de juegos requieren reiniciar para cargar la nueva partida guardada. ¿Quieres reiniciar ahora? - + Failed to open save file: %1 Error al abrir el archivo de guardado: %1 - + Failed to open game file: %1 Error al abrir el archivo del juego: %1 - + Can't yank pack in unexpected platform! - ¡No se puede remover el cartucho en esta plataforma! + ¡No se puede quitar el cartucho en esta plataforma! - + Failed to open snapshot file for reading: %1 Error al leer del archivo de captura: %1 - + Failed to open snapshot file for writing: %1 Error al escribir al archivo de captura: %1 @@ -413,19 +436,19 @@ Tamaño de la descarga: %3 QGBA::CoreManager - + Failed to open game file: %1 Error al abrir el archivo del juego: %1 - + Could not load game. Are you sure it's in the correct format? No se pudo cargar el juego. ¿Estás seguro de que está en el formato correcto? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). - Error al abrir el archivo de guardado; las partidas guardadas no se pueden actualizar. Por favor, asegúrese de que es posible escribir en el directorio de partidas guardadas sin necesidad de privilegios adicionales (Por ejemplo, UAC en Windows). + Error al abrir el archivo de guardado; las partidas guardadas no se pueden actualizar. Por favor, asegúrate de que es posible escribir en el directorio de partidas guardadas sin necesidad de privilegios adicionales (por ejemplo, UAC en Windows). @@ -449,9 +472,9 @@ Tamaño de la descarga: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing - No se ha podido abrir el historial de la linea de comandos para escritura + No se ha podido abrir el historial de la línea de comandos para escritura @@ -464,7 +487,7 @@ Tamaño de la descarga: %3 Local computer - Computadora local + Ordenador local @@ -494,11 +517,205 @@ Tamaño de la descarga: %3 Couldn't Connect - + No se pudo conectar Could not connect to Dolphin. + No se pudo conectar a Dolphin. + + + + QGBA::ForwarderGenerator + + + 3DS + 3DS + + + + Vita + Vita + + + + QGBA::ForwarderGenerator3DS + + + Icon + Icono + + + + Banner + Banner + + + + QGBA::ForwarderGeneratorVita + + + Bubble + Burbujas + + + + Background + En segundo plano + + + + Startup + Puesta en marcha + + + + QGBA::ForwarderView + + + Create forwarder + Crear autocargador + + + + Files + Archivos + + + + ROM file: + Archivo ROM: + + + + + + Browse + Visite + + + + Output filename: + Nombre del archivo de salida: + + + + Forwarder base: + base del transportista: + + + + Latest stable version + Última versión estable + + + + Latest development build + Última versión de desarrollo + + + + Specific file + Archivo específico + + + + Base file: + Archivo básico: + + + + System + Sistema + + + + 3DS + 3DS + + + + Vita + Vita + + + + Presentation + Presentación + + + + Title: + Título: + + + + Images: + Imágenes: + + + + Use default image + Utilizar la imagen por defecto + + + + Preferred size: + Tamaño preferido: + + + + Select image file + Seleccione un archivo de imagen + + + + Select ROM file + Seleccione el archivo ROM + + + + Select output filename + Seleccione el nombre del archivo de salida + + + + Select base file + Seleccionar el archivo inicial + + + + Build finished + Construcción finalizada + + + + Forwarder finished building + Transmisor terminado de construir + + + + Build failed + Falló la construcción + + + + Failed to build forwarder + No se ha podido crear el autocargador + + + + %1 installable package (*.%2) + Paquete instalable %1 (*.%2) + + + + Select an image + Selecciona una imagen + + + + Image files (*.png *.jpg *.bmp) @@ -522,12 +739,12 @@ Tamaño de la descarga: %3 Backdrop color - Color de telón de fondo (backdrop) + Color de telón de fondo Disable scanline effects - Desactivar efectos de línea de trazado + Desactivar efectos de scanline @@ -537,55 +754,55 @@ Tamaño de la descarga: %3 Reset - Reinicializar + Reiniciar - + Export frame Exportar cuadro - + Portable Network Graphics (*.png) Gráficos de red portátiles (*.png) - + None Ninguno - + Background - Fondo (BG) + Fondo - + Window - Ventana (WIN) + Ventana - + Objwin Objwin - + Sprite Sprite - + Backdrop Telón de fondo (backdrop) - + Frame Cuadro - + %1 %2 %1× {1 %2?} @@ -593,7 +810,7 @@ Tamaño de la descarga: %3 QGBA::GBAApp - + Enable Discord Rich Presence Habilitar Rich Presence en Discord @@ -601,22 +818,22 @@ Tamaño de la descarga: %3 QGBA::GBAKeyEditor - + Clear Button - Limpiar botones + Reestablecer botones - + Clear Analog - Limpiar análogo + Reestablecer sticks analógicos - + Refresh Actualizar - + Set all Configurar todo @@ -641,7 +858,7 @@ Tamaño de la descarga: %3 Write watchpoints behavior - + Guardar el comportamiento de las expresiones vigiladas @@ -749,151 +966,171 @@ Tamaño de la descarga: %3 QGBA::GameBoy - - - - Autodetect - Detección automática - - - - Game Boy (DMG) - - - - - Game Boy Pocket (MGB) - - - - - Super Game Boy (SGB) - - - - - Super Game Boy 2 (SGB) - - - Game Boy Color (CGB) - + + Autodetect + Detección automática - Game Boy Advance (AGB) - + Game Boy (DMG) + Game Boy (DMG) - Super Game Boy Color (SGB + CGB) - + Game Boy Pocket (MGB) + Game Boy Pocket (MGB) - + + Super Game Boy (SGB) + Super Game Boy (SGB) + + + + Super Game Boy 2 (SGB) + Super Game Boy 2 (SGB) + + + + Game Boy Color (CGB) + Game Boy Color (CGB) + + + + Game Boy Advance (AGB) + Game Boy Advance (AGB) + + + + Super Game Boy Color (SGB + CGB) + Super Game Boy Color (SGB + CGB) + + + ROM Only Solo ROM - - - MBC1 - - - - - MBC2 - - - - - MBC3 - - - - - MBC3 + RTC - - - - - MBC5 - - - MBC5 + Rumble - + MBC1 + MBC1 - MBC6 - + MBC2 + MBC2 - MBC7 (Tilt) - + MBC3 + MBC3 - MMM01 - + MBC3 + RTC + MBC3 + RTC - HuC-1 - + MBC5 + MBC5 - HuC-3 - + MBC5 + Rumble + MBC5 + Vibración - Pocket Cam - + MBC6 + MBC6 - TAMA5 - TAMA5 + MBC7 (Tilt) + MBC7 (Ladeado) - Wisdom Tree - + MMM01 + MMM01 - NT (new) - + HuC-1 + HuC-1 - Pokémon Jade/Diamond - + HuC-3 + HuC-3 - BBD - + Pocket Cam + Pocket Cam - Hitek - + TAMA5 + TAMA5 - Sachen (MMC1) - + Wisdom Tree + Wisdom Tree + NT (old 1) + NT (antiguo 1) + + + + NT (old 2) + NT (antiguo 2) + + + + NT (new) + NT (nuevo) + + + + Pokémon Jade/Diamond + Pokémon Jade/Diamante + + + + BBD + BBD + + + + Hitek + Hitek + + + + GGB-81 + GGB-81 + + + + Li Cheng + Li Cheng + + + + Sachen (MMC1) + Sachen (MMC1) + + + Sachen (MMC2) - + Sachen (MMC2) @@ -918,22 +1155,22 @@ Tamaño de la descarga: %3 Background mode - Modo de fondo (BG) + Modo de fondo Mode 0: 4 tile layers - Modo 0: 4 capas de tiles + Modo 0: 4 capas de tesela Mode 1: 2 tile layers + 1 rotated/scaled tile layer - Modo 1: 2 capas de tiles + 1 capa de tiles con rotación/escalado + Modo 1: 2 capas de teselas + 1 capa de tesela con rotación/escalado Mode 2: 2 rotated/scaled tile layers - Modo 2: 2 capas de tiles con rotación/escalado + Modo 2: 2 capas de teselas con rotación/escalado @@ -968,7 +1205,7 @@ Tamaño de la descarga: %3 Linear OBJ tile mapping - Asignación de tiles OBJ lineal + Asignación de teselas OBJ lineal @@ -978,22 +1215,22 @@ Tamaño de la descarga: %3 Enable background 0 - Habilitar BG 0 + Habilitar fondo 0 Enable background 1 - Habilitar BG 1 + Habilitar fondo 1 Enable background 2 - Habilitar BG 2 + Habilitar fondo 2 Enable background 3 - Habilitar BG 3 + Habilitar fondo 3 @@ -1023,17 +1260,17 @@ Tamaño de la descarga: %3 Currently in VBlank - En VBlank ahora + Ahora en VBlank Currently in HBlank - En HBlank ahora + Ahora en HBlank Currently in VCounter - En VCounter ahora + Ahora en VCounter @@ -1053,12 +1290,12 @@ Tamaño de la descarga: %3 VCounter scanline - Línea de exploración VCounter + Scanline VCounter Current scanline - Línea de exploración actual + Scanline actual @@ -1074,7 +1311,7 @@ Tamaño de la descarga: %3 Tile data base (* 16kB) - Dirección base de tiles (* 16kB) + Dirección base de tesela (* 16kB) @@ -1098,7 +1335,7 @@ Tamaño de la descarga: %3 Tile map base (* 2kB) - Dirección base de asignación de tiles (* 2kB) + Dirección base de asignación de tesela (* 2kB) @@ -1106,13 +1343,13 @@ Tamaño de la descarga: %3 Background dimensions - Dimensiones de BG + Dimensiones de fondo Overflow wraps - Envolver en desbordamiento + Envolver desbordamiento @@ -1160,7 +1397,7 @@ Tamaño de la descarga: %3 Integer part - Parte entera + Parte de entero @@ -1168,7 +1405,7 @@ Tamaño de la descarga: %3 Integer part (low) - Parte entera (baja) + Parte de entero (baja) @@ -1176,7 +1413,7 @@ Tamaño de la descarga: %3 Integer part (high) - Parte entera (alta) + Parte de entero (alta) @@ -1205,112 +1442,112 @@ Tamaño de la descarga: %3 Window 0 enable BG 0 - Window 0 habilitar BG 0 + Ventana 0 habilitar fondo 0 Window 0 enable BG 1 - Window 0 habilitar BG 1 + Ventana 0 habilitar fondo 1 Window 0 enable BG 2 - Window 0 habilitar BG 2 + Ventana 0 habilitar fondo 2 Window 0 enable BG 3 - Window 0 habilitar BG 3 + Ventana 0 habilitar fondo 3 Window 0 enable OBJ - Window 0 habilitar OBJ + Ventana 0 habilitar OBJ Window 0 enable blend - Window 0 habilitar mezcla + Ventana 0 habilitar mezcla Window 1 enable BG 0 - Window 1 habilitar BG 0 + Ventana 1 habilitar fondo 0 Window 1 enable BG 1 - Window 1 habilitar BG 1 + Ventana 1 habilitar fondo 1 Window 1 enable BG 2 - Window 1 habilitar BG 2 + Ventana 1 habilitar fondo 2 Window 1 enable BG 3 - Window 1 habilitar BG 3 + Ventana 1 habilitar fondo 3 Window 1 enable OBJ - Window 1 habilitar OBJ + Ventana 1 habilitar OBJ Window 1 enable blend - Window 1 habilitar mezcla + Ventana 1 habilitar mezcla Outside window enable BG 0 - Window externa habilitar BG 0 + Ventana externa habilitar fondo 0 Outside window enable BG 1 - Window externa habilitar BG 1 + Ventana externa habilitar fondo 1 Outside window enable BG 2 - Window externa habilitar BG 2 + Ventana externa habilitar fondo 2 Outside window enable BG 3 - Window externa habilitar BG 3 + Ventana externa habilitar fondo 3 Outside window enable OBJ - Window externa habilitar OBJ + Ventana externa habilitar OBJ Outside window enable blend - Outside window habilitar mezcla + Ventana externa habilitar mezcla OBJ window enable BG 0 - OBJ window habilitar BG 0 + Ventana OBJ habilitar fondo 0 OBJ window enable BG 1 - OBJ window habilitar BG 1 + Ventana OBJ habilitar fondo 1 OBJ window enable BG 2 - OBJ window habilitar BG 2 + Ventana OBJ habilitar fondo 2 OBJ window enable BG 3 - OBJ window habilitar BG 3 + Ventana OBJ habilitar fondo 3 @@ -1325,42 +1562,42 @@ Tamaño de la descarga: %3 Background mosaic size vertical - Tamaño vertical mosaico BG + Tamaño vertical de mosaico de fondo Background mosaic size horizontal - Tamaño horizontal mosaico BG + Tamaño horizontal de mosaico de fondo Object mosaic size vertical - Tamaño vertical mosaico OBJ + Tamaño vertical de mosaico de objeto Object mosaic size horizontal - Tamaño horizontal mosaico OBJ + Tamaño horizontal de mosaico de objeto BG 0 target 1 - BG 0 objetivo 1 + Fondo 0 objetivo 1 BG 1 target 1 - BG 1 objetivo 1 + Fondo 1 objetivo 1 BG 2 target 1 - BG 2 objetivo 1 + Fondo 2 objetivo 1 BG 3 target 1 - BG 3 objetivo 1 + Fondo 3 objetivo 1 @@ -1400,22 +1637,22 @@ Tamaño de la descarga: %3 BG 0 target 2 - BG 0 objetivo 2 + Fondo 0 objetivo 2 BG 1 target 2 - BG 1 objetivo 2 + Fondo 1 objetivo 2 BG 2 target 2 - BG 2 objetivo 2 + Fondo 2 objetivo 2 BG 3 target 2 - BG 3 objetivo 2 + Fondo 3 objetivo 2 @@ -1539,7 +1776,7 @@ Tamaño de la descarga: %3 Reset - Reinicializar + Reiniciar @@ -1738,7 +1975,7 @@ Tamaño de la descarga: %3 Channel A reset - Canal A reinicializar + Reiniciar canal A @@ -1758,7 +1995,7 @@ Tamaño de la descarga: %3 Channel B reset - Canal B reinicializar + Reiniciar canal B @@ -2108,7 +2345,7 @@ Tamaño de la descarga: %3 Video Capture - Captura de video + Captura de vídeo @@ -2543,7 +2780,7 @@ Tamaño de la descarga: %3 Background tile map - Mapa de tiles en fondo (BG) + Mapa de tesela de fondo @@ -2560,7 +2797,7 @@ Tamaño de la descarga: %3 Background tile data - Datos de tiles de fondo + Datos de tesela de fondo @@ -2580,7 +2817,7 @@ Tamaño de la descarga: %3 Window tile map - Mapa de tiles en window + Mapa de tesela en pantalla @@ -2769,26 +3006,11 @@ Tamaño de la descarga: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - Menú - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Tamaño de la descarga: %3 Dañado - + Slot %1 Espacio %1 @@ -3107,7 +3329,7 @@ Tamaño de la descarga: %3 Tile base - Base tiles + Base de tesela @@ -3136,39 +3358,39 @@ Tamaño de la descarga: %3 Espejar - + None Ninguno - + Both Ambos - + Horizontal Horizontal - + Vertical Vertical - - - + + + N/A n/d - + Export map Exportar mapa - + Portable Network Graphics (*.png) Gráficos de red portátiles (*.png) @@ -3419,22 +3641,22 @@ Tamaño de la descarga: %3 Actualizar - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 byte%2 @@ -3525,6 +3747,24 @@ Tamaño de la descarga: %3 Cuadro %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -3550,7 +3790,7 @@ Tamaño de la descarga: %3 Transform - Transform + Transformar @@ -3631,7 +3871,7 @@ Tamaño de la descarga: %3 Tile - Tile + Tesela @@ -3909,7 +4149,7 @@ Tamaño de la descarga: %3 Export BG - Exportar BG + Exportar fondo @@ -4008,12 +4248,12 @@ Tamaño de la descarga: %3 Save Printout - + Guardar impresión Portable Network Graphics (*.png) - + Portable Network Graphics (*.png) @@ -4023,6 +4263,7 @@ Tamaño de la descarga: %3 + (unknown) (desconocido) @@ -4066,13 +4307,18 @@ Tamaño de la descarga: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView Bug report archive - Archivo del reporte de bugs + Archivo del informe de errores @@ -4082,12 +4328,12 @@ Tamaño de la descarga: %3 Generate Bug Report - Generar informe de defecto + Generar informe de error <html><head/><body><p>To file a bug report, please first generate a report file to attach to the bug report you're about to file. It is recommended that you include the save files, as these often help with debugging issues. This will collect some information about the version of {projectName} you're running, your configuration, your computer, and the game you currently have open (if any). Once this collection is completed you can review all of the information gathered below and save it to a zip file. The collection will automatically attempt to redact any personal information, such as your username if it's in any of the paths gathered, but just in case you can edit it afterwards. After you have generated and saved it, please click the button below or go to <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> to file the bug report on GitHub. Make sure to attach the report you generated!</p></body></html> - <html><head/><body><p>Antes de enviar un reporte de errores, primero genera un archivo de reporte para enviarlo como adjunto. Recomendamos adjuntar los archivos de guardado ya que puede ayudar con la investigación de reportes. Esto recopilara alguna información sobre la versión de {projectName} que corres, su configuración, su computadora, y el juego que tiene abierto (si alguno). Cuando esta colección termine, puede visualizar toda la información y guardarla a un archivo ZIP. Este proceso intentara eliminar automáticamente sus datos personales (como su usuario, si se encuentra en algunas de las rutas de directorio generadas), pero las puede modificar luego por si acaso. Luego generar y guardar el reporte, pulse el botón inferior o visite <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> para presentar el reporte en GitHub. ¡Asegúrese de agregar el archivo del reporte que ha generado!</p></body></html> + <html><head/><body><p>Antes de enviar un informe de errores, por favor primero genera un archivo de reporte para enviarlo como adjunto. Recomendamos adjuntar los archivos de guardado ya que puede ayudar con la investigación de reportes. Esto recopilará información sobre la versión de {projectName} que estás ejecutando y su configuración, tu ordenador, y el juego que tienes abierto (si hay alguno). Cuando esto termine, puedes ver toda la información y guardarla en un archivo ZIP. Este proceso intentará eliminar automáticamente tus datos personales (como tu usuario, si se encuentra en algunas de las rutas de directorio generadas), pero siempre se puede modificiar luego. Tras generar y guardar el reporte, pulsa el botón inferior o visita <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> para subirlo a GitHub. ¡Asegúrate de adjuntar el informe que has generado!</p></body></html> @@ -4107,12 +4353,12 @@ Tamaño de la descarga: %3 Include save file - Incluir archivo de guardado + Incluir partida guardada Create and include savestate - Crear y incluir archivo de estado + Crear e incluir archivo de estado @@ -4173,7 +4419,7 @@ Tamaño de la descarga: %3 No se encontraron conversiones validas - + Cannot convert save games between platforms No se pueden convertir los estados guardados entre plataformas distintas @@ -4199,92 +4445,97 @@ Tamaño de la descarga: %3 Archivo de salida - + %1 %2 save game %1 %2 juego guardado - + little endian little-endian - + big endian big-endian - + SRAM SRAM - + %1 flash %1 flash - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 MBC2 empacado - + unpacked MBC2 MBC2 desempacado - + MBC6 flash flash MBC6 - + MBC6 combined SRAM + flash SRAM + flash combinados MBC6 - + MBC6 SRAM SRAM MBC6 - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game %1 estado guardado con juego guardado %2 integrado - + %1 SharkPort %2 save game %1 SharkPort %2 partida guardada - + %1 GameShark Advance SP %2 save game %1 GameShark Advance SP %2 partida guardada @@ -4292,9 +4543,9 @@ Tamaño de la descarga: %3 QGBA::ScriptingTextBuffer - + Untitled buffer - + Búfer sin nombre @@ -4302,52 +4553,52 @@ Tamaño de la descarga: %3 Scripting - + Scripts Run - + Ejecutar File - + Archivo Load recent script - + Cargar script reciente Load script... - + Cargar script... &Reset - &Reinicializar + &Reiniciar 0 - 0 + 0 Select script to load - + Elegir script Lua scripts (*.lua) - + Scripts de Lua (*.lua) All files (*.*) - + Todos los archivos (*.*) @@ -4385,12 +4636,12 @@ Tamaño de la descarga: %3 Offset time - + Tiempo de compensación sec - + seg @@ -4438,95 +4689,105 @@ Tamaño de la descarga: %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimedia - + SDL SDL - + Software (Qt) Software (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (forzar versión 1.x) - + None - Ninguno + Ninguno - + None (Still Image) Nada (imagen estática) - + Keyboard Teclado - + Controllers - Controladores + Mandos - + Shortcuts Atajos de teclado - - + + Shaders Shaders - + Select BIOS Seleccionar BIOS - + Select directory Elegir carpeta - + + Select image + Seleccionar imagen + + + + Image file (*.png *.jpg *.jpeg) + Archivo de imagen (*.png *.jpg *.jpeg) + + + (%1×%2) - + Never Nunca - + Just now Ahora mismo - + Less than an hour ago Hace menos de una hora - + %n hour(s) ago Hace %n hora @@ -4534,7 +4795,7 @@ Tamaño de la descarga: %3 - + %n day(s) ago Hace %n dia @@ -4549,12 +4810,12 @@ Tamaño de la descarga: %3 Audio/Video - Audio/video + Audio/vídeo Gameplay - + Jugabilidad @@ -4599,7 +4860,7 @@ Tamaño de la descarga: %3 Audio driver: - Sistema de audio: + Controlador de audio: @@ -4719,7 +4980,7 @@ Tamaño de la descarga: %3 Display driver: - Sistema de video: + Controlador de vídeo: @@ -4733,7 +4994,7 @@ Tamaño de la descarga: %3 - + frames cuadros @@ -4756,7 +5017,7 @@ Tamaño de la descarga: %3 Video - Video + Vídeo @@ -4777,7 +5038,7 @@ Tamaño de la descarga: %3 Show filename instead of ROM name in library view - Mostrar el nombre del archivo en vez del nombre de la ROM en la vista de librería + Mostrar nombre del archivo en la vista de biblioteca @@ -4788,32 +5049,32 @@ Tamaño de la descarga: %3 When inactive: - Cuando este inactivo: + Cuando esté inactiva: On loading a game: - + Al guardar la partida: Load last state - + Cargar último estado Load cheats - + Cargar trucos Save entered cheats - + Guardar trucos introducidos When minimized: - Cuando este minimizada: + Cuando esté minimizada: @@ -4826,77 +5087,87 @@ Tamaño de la descarga: %3 Mostrar información sobre la emulación al reiniciar - + + Custom border: + + + + Current channel: Canal actual: - + Current version: Versión actual: - + Update channel: - Actualizar canal: + Canal de actualizaciones: - + Available version: Versión disponible: - + (Unknown) (Desconocido) - + Last checked: - Ultima vez comprobado: + Comprobado por última vez: - + Automatically check on start Comprobar automáticamente al inicio - + Check now Comprobar ahora - + + Rewind speed: + + + + Default color palette only Sólo paleta de colores predeterminada - + SGB color palette if available Paleta de color SGB si está disponible - + GBC color palette if available Paleta de color GBC si está disponible - + SGB (preferred) or GBC color palette if available Paleta de colores SGB (preferida) o GBC si está disponible - + Game Boy Camera Cámara Game Boy - + Driver: Controlador: - + Source: Fuente: @@ -4913,7 +5184,7 @@ Tamaño de la descarga: %3 Dynamically update window title - Actualizar titulo de ventana dinámicamente + Actualizar título de ventana dinámicamente @@ -4937,42 +5208,42 @@ Tamaño de la descarga: %3 Cargar datos adicionales de estado: - + Enable VBA bug compatibility in ROM hacks Activar modo de compatibilidad VBA en ROM hacks - + Preset: Ajustes: Show filename instead of ROM name in title bar - Enseñar el nombre de archivo en lugar del nombre de ROM en el titulo de la ventana + Mostrar nombre de archivo en el título de ventana - + Fast forward (held) speed: Avance rápido (mantenido): - + (240×160) (240×160) - + Log to file - Guardar a archivo + Guardar en archivo - + Log to console - Guardar a consola + Escribir en consola - + Select Log File Seleccionar @@ -5014,7 +5285,7 @@ Tamaño de la descarga: %3 Allow opposing input directions - Permitir direcciones opuestas al mismo tiempo + Permitir introducir teclas opuestas al mismo tiempo @@ -5032,43 +5303,43 @@ Tamaño de la descarga: %3 Hablitar Rich Presence en Discord - + Fast forward speed: Avance rápido: - - + + Unbounded Sin límite - + Enable rewind Habilitar el rebobinar - + Rewind history: - Hist. de rebobinado: + Historial de rebobinado: - + Idle loops: Bucles inactivos: - + Run all Ejecutarlos todos - + Remove known Eliminar los conocidos - + Detect and remove Detectar y eliminar @@ -5076,7 +5347,7 @@ Tamaño de la descarga: %3 Screenshot - Pantallazo + Captura de pantalla @@ -5085,179 +5356,180 @@ Tamaño de la descarga: %3 Trucos - + Preload entire ROM into memory - Cargar ROM completa a la memoria + Cargar ROM completa en la memoria - + Autofire interval: Intervalo de turbo: - + Enable Game Boy Player features by default Habilitar funcionalidad de Game Boy Player por defecto - + Video renderer: - Renderizador de video: + Renderizador de vídeo: - + Software Software - + OpenGL enhancements Mejoras para OpenGL - + High-resolution scale: Escala de alta resolución: - + XQ GBA audio (experimental) Mejorar audio GBA (experimental) - + GB BIOS file: Archivo BIOS GB: - - - - - - - - - + + + + + + + + + + Browse Examinar - + Use BIOS file if found - Usar archivo BIOS si fue encontrado + Usar archivo BIOS si está disponible - + Skip BIOS intro - Saltar animación de entrada del BIOS + Saltar animación de entrada de la BIOS - + GBA BIOS file: Archivo BIOS GBA: - + GBC BIOS file: Archivo BIOS GBC: - + SGB BIOS file: Archivo BIOS SGB: Periodically autosave state - + Guardar estado automáticamente - + Save games Datos de guardado - - - - - + + + + + Same directory as the ROM - Al mismo directorio que la ROM + En el mismo directorio que la ROM - + Save states Estados de guardado - + Screenshots - Pantallazos + Capturas de pantalla - + Patches Parches - + Cheats Trucos - + Models Modelos - + GB only: Sólo GB: - + SGB compatible: Compatible con SGB: - + GBC only: Sólo GBC: - + GBC compatible: Compatible con GBC: - + SGB and GBC compatible: Compatible con SGB y GBC: - + Game Boy palette Paleta de Game Boy - + Default BG colors: Colores de fondo por defecto: - + Super Game Boy borders Bordes de Super Game Boy - + Default sprite colors 1: Colores de sprite 1 por defecto: - + Default sprite colors 2: Colores de sprite 2 por defecto: @@ -5270,27 +5542,28 @@ Tamaño de la descarga: %3 No hay shader activo - + + Load shader Cargar shader - + No shader loaded No hay shader cargado - + by %1 por %1 - + Preprocessing Preproceso - + Pass %1 Paso %1 @@ -5333,17 +5606,17 @@ Tamaño de la descarga: %3 QGBA::ShortcutModel - + Action Acción - + Keyboard Teclado - + Gamepad Mando @@ -5376,7 +5649,7 @@ Tamaño de la descarga: %3 Export tiles - Exportar tiles + Exportar teselas @@ -5392,7 +5665,7 @@ Tamaño de la descarga: %3 Tiles - Tiles + Teselas @@ -5412,7 +5685,7 @@ Tamaño de la descarga: %3 Palette - Paleta + Paleta @@ -5422,7 +5695,7 @@ Tamaño de la descarga: %3 Tiles per row - Tiles por fila + Teselas por fila @@ -5432,22 +5705,22 @@ Tamaño de la descarga: %3 Displayed tiles - + Teselas mostradas Only BG tiles - Solo BG tiles + Sólo teselas de fondo Only OBJ tiles - Solo OBJ tiles + Sólo teselas de objeto Both - Ambos + Ambos @@ -5462,25 +5735,25 @@ Tamaño de la descarga: %3 QGBA::VideoView - - - Failed to open output video file: %1 - Error al abrir el archivo de video de salida: %1 - - Native (%0x%1) - Native (%0x%1) + Failed to open output video file: %1 + Error al abrir el archivo de vídeo de salida: %1 - + + Native (%0x%1) + Nativo (%0x%1) + + + Select output file Seleccionar archivo de salida Record Video - Grabar video + Grabar vídeo @@ -5567,7 +5840,7 @@ Tamaño de la descarga: %3 &Native - &NAtivo + &Nativo @@ -5608,7 +5881,7 @@ Tamaño de la descarga: %3 WavPack - + WavPack @@ -5684,100 +5957,80 @@ Tamaño de la descarga: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - ROMs de Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - ROMs de Game Boy (%1) - - - - All ROMs (%1) - Todas las ROMs (%1) - - - - %1 Video Logs (*.mvl) - Video-registros de %1 (*.mvl) - - - + Archives (%1) Contenedores (%1) - - - + + + Select ROM Seleccionar ROM - + Select folder Seleccionar carpeta - - + + Select save Seleccionar guardado - + Select patch Seleccionar parche - + Patches (*.ips *.ups *.bps) Parches (*.ips *.ups *.bps) - + Select e-Reader dotcode Seleccionar dotcode del e-Reader - + e-Reader card (*.raw *.bin *.bmp) Tarjeta e-Reader (*.raw *.bin *.bmp) - + Select image Seleccionar imagen - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Archivo de imagen (*.png *.gif *.jpg *.jpeg);;Todos los archivos (*) - + GameShark saves (*.sps *.xps) Guardados de GameShark (*.sps *.xps) - + Select video log - Seleccionar video-registro + Seleccionar registro de vídeo - + Video logs (*.mvl) - Video-registros (*.mvl) + Registros de vídeo (*.mvl) - + Crash Cierre inesperado - + The game has crashed with the following error: %1 @@ -5786,740 +6039,770 @@ Tamaño de la descarga: %3 %1 - + Unimplemented BIOS call Llamada a BIOS no implementada - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Este juego utiliza una llamada al BIOS que no se ha implementado. Utiliza el BIOS oficial para obtener la mejor experiencia. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. No se pudo crear un dispositivo de pantalla apropiado, recurriendo a software. Los juegos pueden funcionar lentamente, especialmente con ventanas grandes. - + Really make portable? ¿Hacer "portable"? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? Esto hará que el emulador cargue su configuración desde el mismo directorio que el ejecutable. ¿Quieres continuar? - + Restart needed Reinicio necesario - + Some changes will not take effect until the emulator is restarted. Algunos cambios no surtirán efecto hasta que se reinicie el emulador. - + - Player %1 of %2 - Jugador %1 de %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File &Archivo - + Load &ROM... Cargar &ROM... - + Load ROM in archive... Cargar ROM desde contenedor... - + Add folder to library... Agregar carpeta a la biblioteca... - + Save games - Datos de guardado + Datos de guardado - + Automatically determine Determinar automáticamente - + Use player %0 save game Usar la partida guardada del jugador %0 - + Load &patch... Cargar &parche... - + Boot BIOS Arrancar BIOS - + Replace ROM... Reemplazar ROM... - + ROM &info... &Información de la ROM... - + Recent - Recientes + Cargar reciente - + Make portable - Hacer "portable" + Crear instalación portable - + &Load state Ca&rgar estado - + Report bug... - Reportar bug... + Reportar error... - + About... Acerca de... - + Game Pak sensors... Sensores del cartucho... - + Clear Limpiar - + Load state file... Cargar archivo de estado... - + Save games (%1) Juegos guardados (%1) - + Select save game Elegir juego guardado - + mGBA save state files (%1) Archivos estados guardados mGBA (%1) - - + + Select save state Elegir estado guardado - + Select e-Reader card images Elegir imágenes de tarjeta e-Reader - + Image file (*.png *.jpg *.jpeg) Archivo de imagen (*.png *.jpg *.jpeg) - + Conversion finished Conversión terminada - + %1 of %2 e-Reader cards converted successfully. %1 de %2 tarjetas e-Reader convertidas con éxito. - + Load alternate save game... - Elegir juego guardado alterno... + Cargar partida guardada alternativa... - + Load temporary save game... - Elegir juego guardado temporal... + Cargar partida guardada temporal... - + Convert e-Reader card image to raw... - Convertir imagen de tarjeta e-Reader a raw... + Convertir imagen de tarjeta e-Reader a archivo en bruto... - + &Save state Guardar e&stado - + Save state file... Guardar archivo de estado... - + Quick load Cargado rápido - + Quick save Guardado rápido - + Load recent Cargar reciente - + Save recent Guardar reciente - + Undo load state Deshacer cargar estado - + Undo save state Deshacer guardar estado - - + + State &%1 Estado &%1 - + Load camera image... - Cargar imagen para la cámara... + Cargar imagen para cámara... - + Convert save game... Convertir juego guardado... - + GameShark saves (*.gsv *.sps *.xps) Partidas guardadas de GameShark (*.gsv *.sps *.xps) - + Reset needed Reinicio necesario - + Some changes will not take effect until the game is reset. Algunos cambios no tendrán efecto hasta que se reinicie el juego. - + New multiplayer window Nueva ventana multijugador - + Connect to Dolphin... Conectar a Dolphin... - + E&xit Salir (&X) - + &Emulation &Emulación - + &Reset - &Reinicializar + &Reiniciar - + Sh&utdown Apagar (&U) - + Yank game pak - Tirar del cartucho + Sacar cartucho - + &Pause &Pausar - + &Next frame Cuadro siguie&nte - + Fast forward (held) Avance rápido (mantener) - + &Fast forward &Avance rápido - + Fast forward speed Velocidad de avance rápido - + Unbounded Sin límite - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Rebobinar (mantener) - + Re&wind Re&bobinar - + Step backwards Paso hacia atrás - + Solar sensor Sensor solar - + Increase solar level Subir nivel - + Decrease solar level Bajar nivel - + Brightest solar level Más claro - + Darkest solar level Más oscuro - + Brightness %1 Brillo %1 - + Audio/&Video - Audio/&video + Audio/&vídeo - + Frame size Tamaño del cuadro - + Toggle fullscreen Pantalla completa - + Lock aspect ratio Bloquear proporción de aspecto - + Force integer scaling Forzar escala a enteros - + Bilinear filtering Filtro bilineal - + Frame&skip &Salto de cuadros - + Mute Silenciar - + FPS target Objetivo de FPS - + Native (59.7275) Nativo (59,7275) - + Take &screenshot Tomar pan&tallazo - + F12 F12 - + Game Boy Printer... Game Boy Printer... - + BattleChip Gate... BattleChip Gate... - + %1× %1× - + Interframe blending Mezcla entre cuadros - + Record A/V... Grabar A/V... - + Video layers - Capas de video + Capas de vídeo - + Audio channels Canales de audio - + Adjust layer placement... Ajustar ubicación de capas... - + &Tools Herramien&tas - + View &logs... Ver re&gistros... - + Game &overrides... Ajustes específic&os por juego... - + Couldn't Start No se pudo iniciar - + Could not start game. No se pudo iniciar el juego. - + Scan e-Reader dotcodes... Escanear dotcodes del e-Reader... - + Import GameShark Save... Importar desde GameShark... - + Export GameShark Save... Exportar a GameShark... - + Record GIF/WebP/APNG... Grabar GIF/WebP/APNG... - + &Cheats... Tru&cos... - + Settings... Ajustes... - + Open debugger console... Abrir consola de depuración... - + Start &GDB server... Iniciar servidor &GDB... - + Scripting... - + Scripts... - - Game state views - + + Create forwarder... + Crear autocargador... + Game state views + Estado del juego + + + View &palette... Ver &paleta... - + View &sprites... Ver &sprites... - + View &tiles... Ver m&osaicos... - + View &map... Ver &mapa... - + &Frame inspector... Inspec&tor de cuadros... - + View memory... Ver memoria... - + Search memory... Buscar memoria... - + View &I/O registers... Ver registros &I/O... - - - Record debug video log... - Grabar registro de depuración de video... - - Stop debug video log - Detener registro de depuración de video + Record debug video log... + Grabar registro de depuración de vídeo... - + + Stop debug video log + Detener registro de depuración de vídeo + + + Exit fullscreen Salir de pantalla completa - + GameShark Button (held) Botón GameShark (mantener) - + Autofire Disparo automático - + Autofire A Disparo automático A - + Autofire B Disparo automático B - + Autofire L Disparo automático L - + Autofire R Disparo automático R - + Autofire Start Disparo automático Start - + Autofire Select Disparo automático Select - + Autofire Up - Disparo automático Arriba + Disparo automático arriba - + Autofire Right - Disparo automático Derecha + Disparo automático derecha - + Autofire Down - Disparo automático Abajo + Disparo automático abajo - + Autofire Left - Disparo automático Izquierda + Disparo automático izquierda QObject - + %1 byte %1 byte - + %1 kiB %1 kiB - + %1 MiB %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + Menú + QShortcut - + Shift Mayús - + Control Ctrl - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/ts/mgba-fr.ts b/src/platform/qt/ts/mgba-fr.ts index df40af0a7..7efbfef1c 100644 --- a/src/platform/qt/ts/mgba-fr.ts +++ b/src/platform/qt/ts/mgba-fr.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ROMs de Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROMs de Game Boy (%1) + + + + All ROMs (%1) + Toutes les ROM (%1) + + + + %1 Video Logs (*.mvl) + %1 Journaux vidéo (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Taille du téléchargement : %3 QGBA::ApplicationUpdater - + Stable Stable - + Development Développement - + Unknown Inconnue - + (None) (Aucune) @@ -365,48 +388,48 @@ Taille du téléchargement : %3 QGBA::CoreController - + Reset r%1-%2 %3 Réinitialiser r%1-%2 %3 - - + + Rewinding not currently enabled Le rembobinage n'est pas actuellement activé - + Reset the game? Réinitialiser le jeu ? - + Most games will require a reset to load the new save. Do you want to reset now? La plupart des jeux nécessitent une réinitialisation pour charger la nouvelle sauvegarde. Voulez-vous réinitialiser maintenant ? - + Failed to open save file: %1 Échec de l'ouverture du fichier de sauvegarde : %1 - + Failed to open game file: %1 Échec de l'ouverture du fichier de jeu : %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 Échec de l'ouverture de l'instantané pour lire : %1 - + Failed to open snapshot file for writing: %1 Échec de l'ouverture de l'instantané pour écrire : %1 @@ -414,17 +437,17 @@ Taille du téléchargement : %3 QGBA::CoreManager - + Failed to open game file: %1 Échec de l'ouverture du fichier de jeu : %1 - + Could not load game. Are you sure it's in the correct format? Impossible de charger le jeu. Êtes-vous sûr qu'il est dans le bon format ? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). Impossible d'ouvrir le fichier de sauvegarde ; les sauvegardes en jeu ne peuvent pas être mises à jour. Veuillez vous assurer que le répertoire de sauvegarde est accessible en écriture sans privilèges supplémentaires (par exemple, UAC sous Windows). @@ -450,7 +473,7 @@ Taille du téléchargement : %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -503,6 +526,200 @@ Taille du téléchargement : %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + Arrière plan + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + Parcourir + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -541,52 +758,52 @@ Taille du téléchargement : %3 Réinitialiser - + Export frame Exporter l'image - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Aucun - + Background Arrière plan - + Window Fenêtre - + Objwin Objwin - + Sprite Sprite - + Backdrop Toile de fond - + Frame Cadre - + %1 %2 %1 %2 @@ -594,7 +811,7 @@ Taille du téléchargement : %3 QGBA::GBAApp - + Enable Discord Rich Presence Activer intégration avec Discord @@ -602,22 +819,22 @@ Taille du téléchargement : %3 QGBA::GBAKeyEditor - + Clear Button Bouton d'effacement - + Clear Analog Effacer l'analogique - + Refresh Rafraîchir - + Set all Tout définir @@ -751,148 +968,168 @@ Taille du téléchargement : %3 QGBA::GameBoy - - + + Autodetect Détection automatique - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2780,26 +3017,11 @@ Taille du téléchargement : %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - Menu - QGBA::LibraryTree @@ -2921,7 +3143,7 @@ Taille du téléchargement : %3 Corrompue - + Slot %1 Emplacement %1 @@ -3154,39 +3376,39 @@ Taille du téléchargement : %3 Miroir - + None Aucun - + Both Les deux - + Horizontal Horizontal - + Vertical Vertical - - - + + + N/A s.o. - + Export map Exporter la map - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3437,22 +3659,22 @@ Taille du téléchargement : %3 Rafraîchir - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 octet%2 @@ -3543,6 +3765,24 @@ Taille du téléchargement : %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4041,6 +4281,7 @@ Taille du téléchargement : %3 + (unknown) (inconnu) @@ -4084,6 +4325,11 @@ Taille du téléchargement : %3 CRC32: CRC32 : + + + Save file: + + QGBA::ReportView @@ -4191,7 +4437,7 @@ Taille du téléchargement : %3 - + Cannot convert save games between platforms @@ -4217,92 +4463,97 @@ Taille du téléchargement : %3 - + %1 %2 save game - + little endian - + big endian - + SRAM SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4310,7 +4561,7 @@ Taille du téléchargement : %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4457,95 +4708,105 @@ Taille du téléchargement : %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimédia - + SDL SDL - + Software (Qt) Software (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (version forcée 1.x) - + None Aucun - + None (Still Image) Aucun (Image fixe) - + Keyboard Clavier - + Controllers Contrôleurs - + Shortcuts Raccourcis - - + + Shaders Shaders - + Select BIOS Choisir le BIOS - + Select directory - - (%1×%2) - (%1×%2) + + Select image + Choisir une image - - Never + + Image file (*.png *.jpg *.jpeg) + (%1×%2) + (%1×%2) + + + + Never + + + + Just now - + Less than an hour ago - + %n hour(s) ago @@ -4553,7 +4814,7 @@ Taille du téléchargement : %3 - + %n day(s) ago @@ -4752,7 +5013,7 @@ Taille du téléchargement : %3 - + frames images @@ -4835,42 +5096,42 @@ Taille du téléchargement : %3 - + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now @@ -4911,97 +5172,107 @@ Taille du téléchargement : %3 - + + Custom border: + + + + + Rewind speed: + + + + Models - + GB only: - + SGB compatible: - + GBC only: - + GBC compatible: - + SGB and GBC compatible: - + Game Boy palette - + Preset: - + Default color palette only - + SGB color palette if available - + GBC color palette if available - + SGB (preferred) or GBC color palette if available - + Game Boy Camera - + Driver: - + Source: - + Enable Game Boy Player features by default - + Log to file Journalisation vers le fichier - + Log to console Journalisation vers la console - + Select Log File Sélectionner le fichier de journalisation @@ -5081,48 +5352,48 @@ Taille du téléchargement : %3 Afficher le nom du fichier au lieu du nom de la ROM dans la barre de titre - + Fast forward speed: Vitesse d'avance rapide : - - + + Unbounded Sans limites - + Fast forward (held) speed: Vitesse d'avance rapide (maintenue) : - + Enable rewind Permettre le rembobinage - + Rewind history: Historique du rembobinage : - + Idle loops: Boucles d'inactivité : - + Run all Tout lancer - + Remove known Supprimer les éléments connus - + Detect and remove Détecter et supprimer @@ -5139,144 +5410,145 @@ Taille du téléchargement : %3 Codes de triches - + Preload entire ROM into memory Précharger toute la ROM en mémoire - + Autofire interval: Intervalle de tir automatique : - + Enable VBA bug compatibility in ROM hacks - + Video renderer: Rendu vidéo : - + Software Logiciel(s) - + OpenGL enhancements Améliorations OpenGL - + High-resolution scale: Échelle haute résolution : - + (240×160) (240×160) - + XQ GBA audio (experimental) XQ GBA audio (expérimental) - + GB BIOS file: GB BIOS : - - - - - - - - - + + + + + + + + + + Browse Parcourir - + Use BIOS file if found Utiliser le fichier BIOS si trouvé - + Skip BIOS intro Passer l'intro du BIOS - + GBA BIOS file: GBA BIOS : - + GBC BIOS file: GBC BIOS : - + SGB BIOS file: SGB BIOS : - + Save games Sauvegarder les jeux - - - - - + + + + + Same directory as the ROM Même répertoire que la ROM - + Save states Sauvegarder les états - + Screenshots Captures d'écran - + Patches Correctifs - + Cheats Cheats - + Default BG colors: Couleurs par défaut de l'arrière plan : - + Super Game Boy borders Bordures Super Game Boy - + Default sprite colors 1: Couleurs par défaut de la sprite nº 1 : - + Default sprite colors 2: Couleurs par défaut de la sprite n°2 : @@ -5289,27 +5561,28 @@ Taille du téléchargement : %3 Aucun shader actif - + + Load shader Charger un shader - + No shader loaded Aucun shader chargé - + by %1 de %1 - + Preprocessing Pré-traitement - + Pass %1 Passe %1 @@ -5352,17 +5625,17 @@ Taille du téléchargement : %3 QGBA::ShortcutModel - + Action Action - + Keyboard Clavier - + Gamepad Manette de jeu @@ -5482,17 +5755,17 @@ Taille du téléchargement : %3 QGBA::VideoView - + Failed to open output video file: %1 Impossible d'ouvrir le fichier vidéo de sortie : %1 - + Native (%0x%1) Natif (%0x%1) - + Select output file Choisir le fichier de sortie @@ -5703,120 +5976,100 @@ Taille du téléchargement : %3 QGBA::Window - - Game Boy Advance ROMs (%1) - ROMs de Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - ROMs de Game Boy (%1) - - - - All ROMs (%1) - Toutes les ROM (%1) - - - - %1 Video Logs (*.mvl) - %1 Journaux vidéo (*.mvl) - - - + Archives (%1) Archives (%1) - - - + + + Select ROM Choisir une ROM - + Select folder Choisir un dossier - - + + Select save Choisir une sauvegarde - + Select patch Sélectionner un correctif - + Patches (*.ips *.ups *.bps) Correctifs/Patches (*.ips *.ups *.bps) - + Select e-Reader dotcode Sélectionnez le numéro de point du e-Reader - + e-Reader card (*.raw *.bin *.bmp) e-Reader carte (*.raw *.bin *.bmp) - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Select image Choisir une image - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Image (*.png *.gif *.jpg *.jpeg);;Tous les fichiers (*) - + GameShark saves (*.sps *.xps) Sauvegardes GameShark (*.sps *.xps) - + Select video log Sélectionner un journal vidéo - + Video logs (*.mvl) Journaux vidéo (*.mvl) - + Crash Plantage - + The game has crashed with the following error: %1 @@ -5825,664 +6078,679 @@ Taille du téléchargement : %3 %1 - + Unimplemented BIOS call Requête au BIOS non supporté - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Ce jeu utilise un appel BIOS qui n'est pas implémenté. Veuillez utiliser le BIOS officiel pour une meilleure expérience. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Échec de la création d'un périphérique d'affichage approprié, retour à l'affichage du logiciel. Les jeux peuvent fonctionner lentement, en particulier avec des fenêtres plus grandes. - + Really make portable? Vraiment rendre portable ? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? Cela amènera l'émulateur à charger sa configuration depuis le même répertoire que l'exécutable. Souhaitez vous continuer ? - + Restart needed Un redémarrage est nécessaire - + Some changes will not take effect until the emulator is restarted. Certains changements ne prendront effet qu'après le redémarrage de l'émulateur. - + - Player %1 of %2 - Joueur %1 of %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File &Fichier - + Load &ROM... Charger une &ROM… - + Load ROM in archive... Charger la ROM d'une archive… - + Add folder to library... Ajouter un dossier à la bibliothèque… - + Load &patch... Charger un c&orrectif… - + Boot BIOS Démarrer le BIOS - + Replace ROM... Remplacer la ROM… - - Game state views + + Increase fast forward speed - - Convert e-Reader card image to raw... + + Decrease fast forward speed - - ROM &info... - &Infos sur la ROM… - - - - Recent - Récent - - - - Make portable - Rendre portable - - - - &Load state - &Charger un état - - - - &Save state - &Sauvegarder un état - - - - Quick load - Chargement rapide - - - - Quick save - Sauvegarde rapide - - - - Load recent - Charger un fichier récent - - - - Save recent - Sauvegarder un fichier récent - - - - Undo load state - Annuler le chargement de l'état - - - - Undo save state - Annuler la sauvegarde de l'état - - - - - State &%1 - État &%1 - - - - Load camera image... - Charger une image de la caméra… - - - - Convert save game... - - - - - New multiplayer window - Nouvelle fenêtre multijoueur - - - - Connect to Dolphin... - - - - - Report bug... - Signalement de l'erreur… - - - - E&xit - &Quitter - - - - &Emulation - &Émulation - - - - &Reset - &Réinitialiser - - - - Sh&utdown - Extin&ction - - - - Yank game pak - Yank game pak - - - - &Pause - &Pause - - - - &Next frame - &Image suivante - - - - Fast forward (held) - Avance rapide (maintenir) - - - - &Fast forward - A&vance rapide - - - - Fast forward speed - Vitesse de l'avance rapide - - - - Unbounded - Sans limites - - - - %0x - %0x - - - - Rewind (held) - Rembobiner (maintenir) - - - - Re&wind - Rem&bobiner - - - - Step backwards - Retour en arrière - - - - Solar sensor - Capteur solaire - - - - Increase solar level - Augmenter le niveau solaire - - - - Decrease solar level - Diminuer le niveau solaire - - - - Brightest solar level - Tester le niveau solaire - - - - Darkest solar level - Assombrir le niveau solaire - - - - Brightness %1 - Luminosité %1 - - - - Audio/&Video - Audio/&Vidéo - - - - Frame size - Taille de l'image - - - - Toggle fullscreen - Basculer en plein écran - - - - Lock aspect ratio - Bloquer les proportions - - - - Force integer scaling - Forcer la mise à l'échelle par des nombres entiers - - - - Bilinear filtering - Filtrage bilinèaire - - - - Frame&skip - &Saut d'image - - - - Mute - Muet - - - - FPS target - FPS ciblé - - - - Take &screenshot - Prendre une ca&pture d'écran - - - - F12 - F12 - - - - Game Boy Printer... - Imprimante GameBoy… - - - - Video layers - Couches vidéo - - - - Audio channels - Canaux audio - - - - Adjust layer placement... - Ajuster la disposition… - - - - &Tools - Ou&tils - - - - View &logs... - Voir les &journaux… - - - - Game &overrides... - - - - - Couldn't Start - N'a pas pu démarrer - - - - Save games (%1) - - - - - Select save game - - - - - mGBA save state files (%1) - - - - - - Select save state - - - - - GameShark saves (*.gsv *.sps *.xps) - - - - - Could not start game. - Impossible de démarrer le jeu. - - - - Load alternate save game... - - - - - Load temporary save game... - - - - - Scan e-Reader dotcodes... - Scanner les dotcodes e-Reader... - - - - Load state file... - Charger le fichier d'état... - - - - Save state file... - Enregistrer le fichier d'état... - - - - Import GameShark Save... - Importer la sauvegarde de GameShark... - - - - Reset needed - - - - - Some changes will not take effect until the game is reset. - - - - - Save games - Sauvegarder les jeux - - - - Export GameShark Save... - Exporter la sauvegarde de GameShark... - - - - Automatically determine - - - - - Use player %0 save game - - - - - About... - À propos de… - - - - BattleChip Gate... - - - - - %1× - %1× - - - - Interframe blending - Mélange d'images - - - - Native (59.7275) - Natif (59.7275) - - - - Record A/V... - Enregistrer A/V... - - - - Record GIF/WebP/APNG... - Enregistrer GIF/WebP/APNG... - - - - Game Pak sensors... - Capteurs de la Game Pak... - - - - &Cheats... - &Cheats… - - - - Settings... - Paramètres… - - - - Open debugger console... - Ouvrir la console de débug… - - - - Start &GDB server... - Démarrer le serveur &GDB… - - - - Scripting... + + Create forwarder... + Game state views + + + + + Convert e-Reader card image to raw... + + + + + ROM &info... + &Infos sur la ROM… + + + + Recent + Récent + + + + Make portable + Rendre portable + + + + &Load state + &Charger un état + + + + &Save state + &Sauvegarder un état + + + + Quick load + Chargement rapide + + + + Quick save + Sauvegarde rapide + + + + Load recent + Charger un fichier récent + + + + Save recent + Sauvegarder un fichier récent + + + + Undo load state + Annuler le chargement de l'état + + + + Undo save state + Annuler la sauvegarde de l'état + + + + + State &%1 + État &%1 + + + + Load camera image... + Charger une image de la caméra… + + + + Convert save game... + + + + + New multiplayer window + Nouvelle fenêtre multijoueur + + + + Connect to Dolphin... + + + + + Report bug... + Signalement de l'erreur… + + + + E&xit + &Quitter + + + + &Emulation + &Émulation + + + + &Reset + &Réinitialiser + + + + Sh&utdown + Extin&ction + + + + Yank game pak + Yank game pak + + + + &Pause + &Pause + + + + &Next frame + &Image suivante + + + + Fast forward (held) + Avance rapide (maintenir) + + + + &Fast forward + A&vance rapide + + + + Fast forward speed + Vitesse de l'avance rapide + + + + Unbounded + Sans limites + + + + %0x + %0x + + + + Rewind (held) + Rembobiner (maintenir) + + + + Re&wind + Rem&bobiner + + + + Step backwards + Retour en arrière + + + + Solar sensor + Capteur solaire + + + + Increase solar level + Augmenter le niveau solaire + + + + Decrease solar level + Diminuer le niveau solaire + + + + Brightest solar level + Tester le niveau solaire + + + + Darkest solar level + Assombrir le niveau solaire + + + + Brightness %1 + Luminosité %1 + + + + Audio/&Video + Audio/&Vidéo + + + + Frame size + Taille de l'image + + + + Toggle fullscreen + Basculer en plein écran + + + + Lock aspect ratio + Bloquer les proportions + + + + Force integer scaling + Forcer la mise à l'échelle par des nombres entiers + + + + Bilinear filtering + Filtrage bilinèaire + + + + Frame&skip + &Saut d'image + + + + Mute + Muet + + + + FPS target + FPS ciblé + + + + Take &screenshot + Prendre une ca&pture d'écran + + + + F12 + F12 + + + + Game Boy Printer... + Imprimante GameBoy… + + + + Video layers + Couches vidéo + + + + Audio channels + Canaux audio + + + + Adjust layer placement... + Ajuster la disposition… + + + + &Tools + Ou&tils + + + + View &logs... + Voir les &journaux… + + + + Game &overrides... + + + + + Couldn't Start + N'a pas pu démarrer + + + + Save games (%1) + + + + + Select save game + + + + + mGBA save state files (%1) + + + + + + Select save state + + + + + GameShark saves (*.gsv *.sps *.xps) + + + + + Could not start game. + Impossible de démarrer le jeu. + + + + Load alternate save game... + + + + + Load temporary save game... + + + + + Scan e-Reader dotcodes... + Scanner les dotcodes e-Reader... + + + + Load state file... + Charger le fichier d'état... + + + + Save state file... + Enregistrer le fichier d'état... + + + + Import GameShark Save... + Importer la sauvegarde de GameShark... + + + + Reset needed + + + + + Some changes will not take effect until the game is reset. + + + + + Save games + Sauvegarder les jeux + + + + Export GameShark Save... + Exporter la sauvegarde de GameShark... + + + + Automatically determine + + + + + Use player %0 save game + + + + + About... + À propos de… + + + + BattleChip Gate... + + + + + %1× + %1× + + + + Interframe blending + Mélange d'images + + + + Native (59.7275) + Natif (59.7275) + + + + Record A/V... + Enregistrer A/V... + + + + Record GIF/WebP/APNG... + Enregistrer GIF/WebP/APNG... + + + + Game Pak sensors... + Capteurs de la Game Pak... + + + + &Cheats... + &Cheats… + + + + Settings... + Paramètres… + + + + Open debugger console... + Ouvrir la console de débug… + + + + Start &GDB server... + Démarrer le serveur &GDB… + + + + Scripting... + + + + View &palette... Voir la &palette… - + View &sprites... Voir les &sprites… - + View &tiles... Voir les &tiles… - + View &map... Voir la &map… - + &Frame inspector... Inspecteur de &frame... - + View memory... Voir la mémoire… - + Search memory... Recherche dans la mémoire… - + View &I/O registers... Voir les registres d'&E/S... - + Record debug video log... Enregistrer le journal vidéo de débogage... - + Stop debug video log Arrêter le journal vidéo de débogage - + Exit fullscreen Quitter le plein écran - + GameShark Button (held) Bouton GameShark (maintenir) - + Autofire Tir automatique - + Autofire A Tir automatique A - + Autofire B Tir automatique B - + Autofire L Tir automatique L - + Autofire R Tir automatique R - + Autofire Start Tir automatique Start - + Autofire Select Tir automatique Select - + Autofire Up Tir automatique Up - + Autofire Right Tir automatique Right - + Autofire Down Tir automatique Down - + Autofire Left Tir automatique Gauche - + Clear Vider @@ -6490,55 +6758,70 @@ Taille du téléchargement : %3 QObject - + %1 byte - + %1 kiB - + %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + Menu + QShortcut - + Shift Shift - + Control Control - + Alt Alt - + Meta Méta/Super diff --git a/src/platform/qt/ts/mgba-hu.ts b/src/platform/qt/ts/mgba-hu.ts index 38b8bdd70..4e5f7e1f0 100644 --- a/src/platform/qt/ts/mgba-hu.ts +++ b/src/platform/qt/ts/mgba-hu.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + Game Boy Advance ROMok (%1) + + + + Game Boy ROMs (%1) + Game Boy ROMok (%1) + + + + All ROMs (%1) + Összes ROM (%1) + + + + %1 Video Logs (*.mvl) + + + QGBA::AboutScreen @@ -87,22 +110,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable - + Development - + Unknown - + (None) @@ -359,48 +382,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 Nem sikerült a mentésfájl megnyitása: %1 - + Failed to open game file: %1 Nem sikerült a játékfájl megnyitása: %1 - + Can't yank pack in unexpected platform! A játékkazettát nem lehet kirántani ismeretlen platformon! - + Failed to open snapshot file for reading: %1 A pillanatkép fájljának olvasásra való megnyitása sikertelen: %1 - + Failed to open snapshot file for writing: %1 A pillanatkép fájljának írásra való megnyitása sikertelen: %1 @@ -408,17 +431,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 Nem sikerült a játékfájl megnyitása: %1 - + Could not load game. Are you sure it's in the correct format? A játék betöltése nem sikerült. Biztos vagy benne, hogy a megfelelő formátumú? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -444,7 +467,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -497,6 +520,200 @@ Download size: %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + Háttér + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -535,52 +752,52 @@ Download size: %3 Visszaállítás - + Export frame Képkocka exportálása - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Nincs - + Background Háttér - + Window Ablak - + Objwin Objektumablak - + Sprite Sprite - + Backdrop Háttérréteg - + Frame Képkocka - + %1 %2 %1 %2 @@ -588,7 +805,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence Discord Rich Presence engedélyezése @@ -596,22 +813,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button Gombhozzárendelés törlése - + Clear Analog Analóg hozzárendelések törlése - + Refresh Frissítés - + Set all Mind beállítása @@ -745,148 +962,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect Automatikus észlelés - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2764,26 +3001,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- - - - Super (L) - - - - - Super (R) - - - - - Menu - - QGBA::LibraryTree @@ -2905,7 +3127,7 @@ Download size: %3 - + Slot %1 @@ -3131,39 +3353,39 @@ Download size: %3 - + None Nincs - + Both - + Horizontal - + Vertical - - - + + + N/A - + Export map - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3414,22 +3636,22 @@ Download size: %3 Frissítés - + (%0/%1×) - + (⅟%0×) - + (%0×) - + %1 byte%2 @@ -3520,6 +3742,24 @@ Download size: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4018,6 +4258,7 @@ Download size: %3 + (unknown) @@ -4061,6 +4302,11 @@ Download size: %3 CRC32: + + + Save file: + + QGBA::ReportView @@ -4168,7 +4414,7 @@ Download size: %3 - + Cannot convert save games between platforms @@ -4194,92 +4440,97 @@ Download size: %3 - + %1 %2 save game - + little endian - + big endian - + SRAM SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4287,7 +4538,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4433,102 +4684,112 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia - + SDL - + Software (Qt) - - + + OpenGL - + OpenGL (force version 1.x) - + None Nincs - + None (Still Image) - + Keyboard - + Controllers - + Shortcuts - - + + Shaders - + Select BIOS - + Select directory - - (%1×%2) + + Select image - - Never + + Image file (*.png *.jpg *.jpeg) + (%1×%2) + + + + + Never + + + + Just now - + Less than an hour ago - + %n hour(s) ago - + %n day(s) ago @@ -4726,7 +4987,7 @@ Download size: %3 - + frames @@ -4793,37 +5054,37 @@ Download size: %3 - + Default color palette only - + SGB color palette if available - + GBC color palette if available - + SGB (preferred) or GBC color palette if available - + Game Boy Camera - + Driver: - + Source: @@ -4939,98 +5200,108 @@ Download size: %3 - + + Custom border: + + + + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now - + Fast forward speed: - - + + Unbounded - + Fast forward (held) speed: - + Autofire interval: - + Enable rewind - + Rewind history: - + + Rewind speed: + + + + Idle loops: - + Run all - + Remove known - + Detect and remove - + Preload entire ROM into memory @@ -5051,42 +5322,42 @@ Download size: %3 - + Models - + GB only: - + SGB compatible: - + GBC only: - + GBC compatible: - + SGB and GBC compatible: - + Game Boy palette - + Preset: @@ -5103,154 +5374,155 @@ Download size: %3 - + Enable Game Boy Player features by default - + Enable VBA bug compatibility in ROM hacks - + Video renderer: - + Software - + OpenGL enhancements - + High-resolution scale: - + (240×160) - + XQ GBA audio (experimental) - + GB BIOS file: - - - - - - - - - + + + + + + + + + + Browse - + Use BIOS file if found - + Skip BIOS intro - + GBA BIOS file: - + GBC BIOS file: - + SGB BIOS file: - + Save games - - - - - + + + + + Same directory as the ROM - + Save states - + Screenshots - + Patches - + Cheats Csalások - + Log to file - + Log to console - + Select Log File - + Default BG colors: - + Default sprite colors 1: - + Default sprite colors 2: - + Super Game Boy borders @@ -5263,27 +5535,28 @@ Download size: %3 - + + Load shader - + No shader loaded - + by %1 - + Preprocessing - + Pass %1 @@ -5326,17 +5599,17 @@ Download size: %3 QGBA::ShortcutModel - + Action - + Keyboard - + Gamepad @@ -5456,17 +5729,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file Kimeneti fájl kiválasztása @@ -5677,784 +5950,779 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - - - - - Game Boy ROMs (%1) - - - - - All ROMs (%1) - - - - - %1 Video Logs (*.mvl) - - - - + Archives (%1) - - - + + + Select ROM - + Select folder - - + + Select save - + Select patch - + Patches (*.ips *.ups *.bps) - + Select e-Reader dotcode - + e-Reader card (*.raw *.bin *.bmp) - + Select image - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) - + GameShark saves (*.sps *.xps) - + Select video log - + Video logs (*.mvl) - + Crash - + The game has crashed with the following error: %1 - + Couldn't Start - + Could not start game. - + Unimplemented BIOS call - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. - + Really make portable? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - + Restart needed - + Some changes will not take effect until the emulator is restarted. - + - Player %1 of %2 - + %1 - %2 - + %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File - + Load &ROM... - + Load ROM in archive... - + Add folder to library... - + Save games (%1) - + Select save game - + mGBA save state files (%1) - - + + Select save state - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Load alternate save game... - + Load temporary save game... - + Load &patch... - + Boot BIOS - + Replace ROM... - + Scan e-Reader dotcodes... - + Convert e-Reader card image to raw... - + ROM &info... - + Recent - + Make portable - + &Load state - + Load state file... - + &Save state - + Save state file... - + Quick load - + Quick save - + Load recent - + Save recent - + Undo load state - + Undo save state - - + + State &%1 - + Load camera image... - + Convert save game... - + GameShark saves (*.gsv *.sps *.xps) - + Reset needed - + Some changes will not take effect until the game is reset. - + Save games - + Import GameShark Save... - + Export GameShark Save... - + Automatically determine - + Use player %0 save game - + New multiplayer window - + Connect to Dolphin... - + Report bug... - + About... - + E&xit - + &Emulation - + &Reset - + Sh&utdown - + Yank game pak - + &Pause - + &Next frame - + Fast forward (held) - + &Fast forward - + Fast forward speed - + Unbounded - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) - + Re&wind - + Step backwards - + Solar sensor - + Increase solar level - + Decrease solar level - + Brightest solar level - + Darkest solar level - + Brightness %1 - + Game Boy Printer... - + BattleChip Gate... - + Audio/&Video - + Frame size - + %1× %1× - + Toggle fullscreen - + Lock aspect ratio - + Force integer scaling - + Interframe blending - + Bilinear filtering - + Frame&skip - + Mute - + FPS target - + Native (59.7275) - + Take &screenshot - + F12 - + Record A/V... - + Record GIF/WebP/APNG... - + Video layers - + Audio channels - + Adjust layer placement... - + &Tools - + View &logs... - + Game &overrides... - + Game Pak sensors... - + &Cheats... - + + Create forwarder... + + + + Settings... - + Open debugger console... - + Start &GDB server... - + Scripting... - + Game state views - + View &palette... - + View &sprites... - + View &tiles... - + View &map... - + &Frame inspector... - + View memory... - + Search memory... - + View &I/O registers... - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear Napló törlése @@ -6462,55 +6730,70 @@ Download size: %3 QObject - + %1 byte - + %1 kiB - + %1 MiB - + GBA - + GB - + ? + + + Super (L) + + + + + Super (R) + + + + + Menu + + QShortcut - + Shift - + Control - + Alt - + Meta diff --git a/src/platform/qt/ts/mgba-it.ts b/src/platform/qt/ts/mgba-it.ts index 45092ddac..a0a0deb5e 100644 --- a/src/platform/qt/ts/mgba-it.ts +++ b/src/platform/qt/ts/mgba-it.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ROM per Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROM per Game Boy (%1) + + + + All ROMs (%1) + Tutte le ROM (%1) + + + + %1 Video Logs (*.mvl) + %1 log Video (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Dimensione del download: %3 QGBA::ApplicationUpdater - + Stable Stabile - + Development Sviluppo - + Unknown Sconosciuto - + (None) (Nessuno) @@ -364,48 +387,48 @@ Dimensione del download: %3 QGBA::CoreController - + Reset r%1-%2 %3 Reset r%1-%2 %3 - - + + Rewinding not currently enabled La funzione 'riavvolgi' non è attualmente abilitata - + Reset the game? Riavviare il gioco? - + Most games will require a reset to load the new save. Do you want to reset now? La maggior parte dei giochi richiede un riavvio per caricare il nuovo salvataggio. Vuoi riavviare ora? - + Failed to open save file: %1 Impossibile aprire il file di salvataggio: %1 - + Failed to open game file: %1 Impossibile aprire il file di gioco: %1 - + Can't yank pack in unexpected platform! Non riesco a strappare il pacchetto in una piattaforma inaspettata! - + Failed to open snapshot file for reading: %1 Impossibile aprire il file snapshot per la lettura: %1 - + Failed to open snapshot file for writing: %1 Impossibile aprire il file snapshot per la scrittura: %1 @@ -413,17 +436,17 @@ Dimensione del download: %3 QGBA::CoreManager - + Failed to open game file: %1 Impossibile aprire il file di gioco: %1 - + Could not load game. Are you sure it's in the correct format? Impossibile caricare il gioco. Sei sicuro che sia nel formato corretto? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). Impossibile aprire il file di salvataggio; i salvataggi in gioco non possono essere aggiornati. Assicurati che la directory di salvataggio sia scrivibile senza privilegi aggiuntivi (ad esempio UAC su Windows). @@ -449,7 +472,7 @@ Dimensione del download: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing Impossibile aprire lo storico della riga di comando in scrittura @@ -502,6 +525,200 @@ Dimensione del download: %3 Impossibile collegarsi a Dolphin. + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + Sfondo + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + Sfoglia + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Dimensione del download: %3 Reset - + Export frame Esporta Frame - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Nessuno - + Background Sfondo - + Window Finestra - + Objwin Objwin - + Sprite Sprite - + Backdrop Sfondo - + Frame Inquadratura - + %1 %2 %1x {1 %2?} @@ -593,7 +810,7 @@ Dimensione del download: %3 QGBA::GBAApp - + Enable Discord Rich Presence Abilita Discord Rich Presence @@ -601,22 +818,22 @@ Dimensione del download: %3 QGBA::GBAKeyEditor - + Clear Button Svuota i pulsanti - + Clear Analog Svuota Analogici - + Refresh Aggiorna - + Set all Imposta tutti @@ -750,148 +967,168 @@ Dimensione del download: %3 QGBA::GameBoy - - + + Autodetect Rilevamento automatico - + Game Boy (DMG) Game Boy (DMG) - + Game Boy Pocket (MGB) Game Boy Pocket (MGB) - + Super Game Boy (SGB) Super Game Boy (SGB) - + Super Game Boy 2 (SGB) Super Game Boy 2 (SGB) - + Game Boy Color (CGB) Game Boy Color (CGB) - + Game Boy Advance (AGB) Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) Super Game Boy Color (SGB + CGB) - + ROM Only Solo ROM - + MBC1 MBC1 - + MBC2 MBC2 - + MBC3 MBC3 - + MBC3 + RTC MBC3 + RTC - + MBC5 MBC5 - + MBC5 + Rumble MBC5 + Tremolio - + MBC6 MBC6 - + MBC7 (Tilt) MBC7 (Tilt) - + MMM01 MMM01 - + HuC-1 HuC-1 - + HuC-3 HuC-3 - + Pocket Cam Pocket Cam - + TAMA5 TAMA5 - + Wisdom Tree Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) NT (nuovo) - + Pokémon Jade/Diamond Pokemon Giada/Diamante - + BBD BBD - + Hitek Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) Sachen (MMC1) - + Sachen (MMC2) Sachen (MMC2) @@ -2769,26 +3006,11 @@ Dimensione del download: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - Menu - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Dimensione del download: %3 Corrotto - + Slot %1 Slot %1 @@ -3136,39 +3358,39 @@ Dimensione del download: %3 Speculare - + None Nessuno - + Both Entrambi - + Horizontal Orizzontale - + Vertical Verticale - - - + + + N/A N/D - + Export map Esporta Mappa - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3419,22 +3641,22 @@ Dimensione del download: %3 Aggiorna - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 byte%2 @@ -3525,6 +3747,24 @@ Dimensione del download: %3 Frame %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4023,6 +4263,7 @@ Dimensione del download: %3 + (unknown) (sconosciuto) @@ -4066,6 +4307,11 @@ Dimensione del download: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4173,7 +4419,7 @@ Dimensione del download: %3 Nessune conversioni valide trovate - + Cannot convert save games between platforms Impossibile convertire salvataggi tra piattaforme @@ -4199,92 +4445,97 @@ Dimensione del download: %3 File output - + %1 %2 save game %1 %2 salvataggio - + little endian little endian - + big endian big endian - + SRAM SRAM - + %1 flash %1 flash - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + OTR - + %1 SRAM %1 SRAM - + packed MBC2 MBC2 compresso - + unpacked MBC2 MBC2 non compresso - + MBC6 flash MBC6 flash - + MBC6 combined SRAM + flash MBC6 combinato con la SRAM + flash - + MBC6 SRAM SRAM MBC6 - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game %1 stato di salvataggio incorporato con il salvataggio %2 - + %1 SharkPort %2 save game %1 SharkPort %2 salvataggio gioco - + %1 GameShark Advance SP %2 save game %1 GameShark Advance SP %2 salvataggio gioco @@ -4292,7 +4543,7 @@ Dimensione del download: %3 QGBA::ScriptingTextBuffer - + Untitled buffer Buffer senza nome @@ -4438,95 +4689,105 @@ Dimensione del download: %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimedia - + SDL SDL - + Software (Qt) Software (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (forza la versione 1.x) - + None Nessuno - + None (Still Image) nessuno (immagine fissa) - + Keyboard Tastiera - + Controllers Controller - + Shortcuts Scorciatoie - - + + Shaders Shader - + Select BIOS Seleziona BIOS - + Select directory Seleziona directory - + + Select image + Seleziona immagine + + + + Image file (*.png *.jpg *.jpeg) + File immagine (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never Mai - + Just now Solo adesso - + Less than an hour ago Meno di un ora fa - + %n hour(s) ago %n ora fa @@ -4534,7 +4795,7 @@ Dimensione del download: %3 - + %n day(s) ago %n giorno fa @@ -4728,7 +4989,7 @@ Dimensione del download: %3 - + frames frame @@ -4816,112 +5077,122 @@ Dimensione del download: %3 Mostra informazioni emulazione su reset - + + Custom border: + + + + Current channel: Canale attuale: - + Current version: Versione attuale: - + Update channel: Canale aggiornamento: - + Available version: Versione disponibile: - + (Unknown) (Sconosciuto) - + Last checked: Vista l'ultima volta: - + Automatically check on start Verifica automaticamente all'avvio - + Check now Verifica adesso - + + Rewind speed: + + + + Models Modelli - + GB only: Solo GB: - + SGB compatible: Compatibile SGB: - + GBC only: Solo GBC: - + GBC compatible: Compatibile BGC: - + SGB and GBC compatible: Compatibile SGB e GBC: - + Game Boy palette Tavolozza Game Boy - + Default color palette only Solo tavolozza colori predefinita - + SGB color palette if available Tavolozza colori SGB se disponibile - + GBC color palette if available Tavolozza colori GBC se disponibile - + SGB (preferred) or GBC color palette if available Tavolozza colori SGB (preferita) o GBC se disponibile - + Game Boy Camera Videocamera Game Boy - + Driver: Driver: - + Source: Sorgente: @@ -4962,12 +5233,12 @@ Dimensione del download: %3 Carica dati extra stato di salvataggio: - + Enable VBA bug compatibility in ROM hacks Abilita compatibilità con i bug di VBA nelle hack delle ROM - + Preset: Profilo: @@ -4987,82 +5258,82 @@ Dimensione del download: %3 Mostra nome file anziché nome ROM nella barra del titolo - + Fast forward (held) speed: Velocità di crociera: - + Enable Game Boy Player features by default Abilita funzionalità Game Boy Player per impostazione predefinita - + Video renderer: Rend. video: - + Software Software - + OpenGL enhancements Miglioramenti OpenGL - + High-resolution scale: Rapporto alta risoluzione: - + (240×160) (240×160) - + XQ GBA audio (experimental) audio XQ GBA (sperimentale) - + Cheats Trucchi - + Log to file Registro log in file - + Log to console Registro log in console - + Select Log File Seleziona file log - + Default BG colors: Colori predefiniti sfondo: - + Super Game Boy borders Bordi Super Game Boy - + Default sprite colors 1: Colori predefiniti sprite 1: - + Default sprite colors 2: Colori predefiniti sprite 2: @@ -5082,36 +5353,37 @@ Dimensione del download: %3 Svuota la cache - + Fast forward speed: Velocità di avanzamento rapido: - - - - - - - - - + + + + + + + + + + Browse Sfoglia - + Use BIOS file if found Usa il file del BIOS se è presente - + Skip BIOS intro Salta intro del BIOS - - + + Unbounded Illimitato @@ -5126,17 +5398,17 @@ Dimensione del download: %3 BIOS - + Run all esegui tutto - + Remove known rimuovi conosciuti - + Detect and remove rileva e rimuovi @@ -5158,7 +5430,7 @@ Dimensione del download: %3 Trucchi - + Enable rewind Abilita riavvolgimento @@ -5193,71 +5465,71 @@ Dimensione del download: %3 Mostra gli FPS nella barra del titolo - + Rewind history: Cronologia riavvolgimento: - + Idle loops: Cicli inattivi: - + Preload entire ROM into memory Precarica ROM in memoria - + Autofire interval: Intervallo Autofire: - + GB BIOS file: File BIOS del GB: - + GBA BIOS file: File BIOS del GBA: - + GBC BIOS file: File BIOS del GBC: - + SGB BIOS file: File BIOS del SGB: - + Save games Salva le partite - - - - - + + + + + Same directory as the ROM Stessa cartella della ROM - + Save states Salvataggio Stati - + Screenshots Schermate - + Patches Patch @@ -5270,27 +5542,28 @@ Dimensione del download: %3 Nessuno shader attivo - + + Load shader Carica shader - + No shader loaded Nessuno shader caricato - + by %1 per %1 - + Preprocessing Pre-elaborazione - + Pass %1 Pass %1 @@ -5333,17 +5606,17 @@ Dimensione del download: %3 QGBA::ShortcutModel - + Action Azione - + Keyboard Tastiera - + Gamepad Gamepad @@ -5463,17 +5736,17 @@ Dimensione del download: %3 QGBA::VideoView - + Failed to open output video file: %1 Errore durante l'archiviazione del video: %1 - + Native (%0x%1) Nativo (%0x%1) - + Select output file Seleziona file di uscita @@ -5684,115 +5957,95 @@ Dimensione del download: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - ROM per Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - ROM per Game Boy (%1) - - - - All ROMs (%1) - Tutte le ROM (%1) - - - - %1 Video Logs (*.mvl) - %1 log Video (*.mvl) - - - + Archives (%1) Archivi (%1) - - - + + + Select ROM Seleziona ROM - - + + Select save Seleziona salvataggio - + Select patch Seleziona patch - + Patches (*.ips *.ups *.bps) Patch (*.ips *.ups *.bps) - + Select e-Reader dotcode Selezione e-Reader dotcode - + e-Reader card (*.raw *.bin *.bmp) Scheda e-Reader (*.raw *.bin *.bmp) - + Select e-Reader card images Seleziona immagini carte e-Reader - + Image file (*.png *.jpg *.jpeg) File immagine (*.png *.jpg *.jpeg) - + Conversion finished Conversione terminata - + %1 of %2 e-Reader cards converted successfully. %1 di %2 carte e-Reader convertite con successo. - + Select image Seleziona immagine - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) File immagine (*.png *.gif *.jpg *.jpeg);;Tutti i file (*) - + GameShark saves (*.sps *.xps) Salvataggi GameShark (*.sps *.xps) - + Select video log Seleziona log video - + Video logs (*.mvl) Log video (*.mvl) - + Crash Errore fatale - + The game has crashed with the following error: %1 @@ -5801,669 +6054,684 @@ Dimensione del download: %3 %1 - + Unimplemented BIOS call BIOS non implementato - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Questo gioco utilizza una chiamata BIOS non implementata. Utilizza il BIOS ufficiale per una migliore esperienza. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Impossibile creare un dispositivo di visualizzazione appropriato, tornando alla visualizzazione software. I giochi possono funzionare lentamente, specialmente con finestre più grandi. - + Really make portable? Vuoi davvero rendere portatile l'applicazione? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? In questo modo l'emulatore carica la propria configurazione dalla stessa cartella dell'eseguibile. Vuoi continuare? - + Restart needed È necessario riavviare - + Some changes will not take effect until the emulator is restarted. Alcune modifiche non avranno effetto finché l'emulatore non verrà riavviato. - + - Player %1 of %2 - Giocatore %1 di %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File File - + Load &ROM... Carica ROM... - + Load ROM in archive... Carica la ROM in archivio... - + Load &patch... Carica patch... - + Boot BIOS Avvia BIOS - + Replace ROM... Sostituisci la ROM... - + Scan e-Reader dotcodes... Scansiona e-Reader dotcode... - + Convert e-Reader card image to raw... Converti immagini carte e-Reader in raw... - + ROM &info... Informazioni ROM... - + Recent Recenti - + Make portable Rendi portatile - + &Load state Carica stato - + &Save state Salva stato - + Quick load Caricamento rapido - + Quick save Salvataggio rapido - + Load recent Carica recente - + Save recent Salva recente - + Undo load state Annulla il caricamento dello stato - + Undo save state Annulla salvataggio stato - - + + State &%1 Stato %1 - + Load camera image... Carica immagine fotocamera... - + Convert save game... Converti salvataggi... - + GameShark saves (*.gsv *.sps *.xps) Salvataggi GameShark (*.gsv *.sps *.xps) - + Reset needed Reset necessario - + Some changes will not take effect until the game is reset. Alcune modifiche non si applicheranno finché il gioco non viene resettato. - + New multiplayer window Nuova finestra multigiocatore - + Connect to Dolphin... Connessione a Dolphin... - + Report bug... Segnala bug... - + E&xit Esci (&X) - + &Emulation Emulazione - + &Reset Reset - + Sh&utdown Spegni (&U) - + Yank game pak Stacca game pak - + &Pause Pausa - + &Next frame Salta il prossimo frame (&N) - + Fast forward (held) Avanzamento rapido (tieni premuto) - + &Fast forward Avanzamento rapido (&F) - + Fast forward speed Velocità di avanzamento rapido - + Unbounded Illimitata - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Riavvolgimento (tieni premuto) - + Re&wind Riavvolgimento (&W) - + Step backwards Torna indietro - + Solar sensor Sensore solare - + Increase solar level Incrementa il livello solare - + Decrease solar level Riduci il livello solare - + Brightest solar level Livello solare massimo - + Darkest solar level Livello solare minimo - + Brightness %1 Luminosità %1 - + Audio/&Video Audio/Video - + Frame size Dimensione frame - + Toggle fullscreen Abilita schermo Intero - + Lock aspect ratio Blocca rapporti aspetto - + Frame&skip Salto frame - + Mute Muto - + FPS target FPS finali - + Take &screenshot Acquisisci schermata - + F12 F12 - + Record GIF/WebP/APNG... Registra GIF / WebP / APNG ... - + Video layers Layers video - + Audio channels Canali audio - + &Tools Strumenti - + View &logs... Visualizza registri (&log)... - + Game &overrides... Valore specifico per il gioco... - + &Cheats... Trucchi... - + + Create forwarder... + + + + Open debugger console... Apri console debugger... - + Start &GDB server... Avvia server GDB... - + Settings... Impostazioni... - + Select folder Seleziona cartella - + Couldn't Start Non è stato possibile avviare - + Could not start game. Non è stato possibile avviare il gioco. - + Add folder to library... Aggiungi cartella alla libreria... - + Load state file... Carica stato di salvataggio... - + Save state file... Salva stato di salvataggio... - + Import GameShark Save... Importa Salvataggio GameShark... - + Export GameShark Save... Esporta Salvataggio GameShark... - + About... Informazioni… - + Force integer scaling Forza ridimensionamento a interi - + Bilinear filtering Filtro bilineare - + Game Boy Printer... Stampante Game Boy... - + Save games (%1) Salvataggi (%1) - + Select save game Seleziona salvataggio - + mGBA save state files (%1) file di stati di salvataggio mGBA (%1) - - + + Select save state Seleziona stato di salvataggio - + Save games Salvataggi - + Load alternate save game... Carica stato di salvataggio alternativo... - + Load temporary save game... Carica salvataggio temporaneo... - + Automatically determine Determina automaticamente - + Use player %0 save game Usa il salvataggio del giocatore %0 - + BattleChip Gate... BattleChip Gate... - + %1× %1x - + Interframe blending Miscelazione dei frame - + Native (59.7275) Nativo (59.7) - + Record A/V... Registra A/V... - + Adjust layer placement... Regola posizionamento layer... - + Game Pak sensors... Sensori Game Pak... - + Scripting... Scripting... - + Game state views Viste degli stati del gioco - + View &palette... Mostra palette... - + View &sprites... Mostra sprites... - + View &tiles... Mostra tiles... - + View &map... Mostra mappa... - + &Frame inspector... &Frame inspector... - + View memory... Mostra memoria... - + Search memory... Ricerca memoria... - + View &I/O registers... Mostra registri I/O... - + Record debug video log... Registra video log di debug... - + Stop debug video log Ferma video log di debug - + Exit fullscreen Esci da Schermo Intero - + GameShark Button (held) Pulsante GameShark (tieni premuto) - + Autofire Pulsanti Autofire - + Autofire A Autofire A - + Autofire B Autofire B - + Autofire L Autofire L - + Autofire R Autofire R - + Autofire Start Autofire Start - + Autofire Select Autofire Select - + Autofire Up Autofire Su - + Autofire Right AAutofire Destra - + Autofire Down Autofire Giù - + Autofire Left Autofire Sinistra - + Clear Pulisci @@ -6471,55 +6739,70 @@ Dimensione del download: %3 QObject - + %1 byte %1 byte - + %1 kiB %1 kiB - + %1 MiB %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + Menu + QShortcut - + Shift Shift - + Control Control - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/ts/mgba-ja.ts b/src/platform/qt/ts/mgba-ja.ts index fb0cfb04c..29e56717f 100644 --- a/src/platform/qt/ts/mgba-ja.ts +++ b/src/platform/qt/ts/mgba-ja.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ゲームボーイアドバンスファイル (%1) + + + + Game Boy ROMs (%1) + ゲームボーイファイル (%1) + + + + All ROMs (%1) + すべてのROM (%1) + + + + %1 Video Logs (*.mvl) + %1ビデオログ (*.mvl) + + QGBA::AboutScreen @@ -41,70 +64,75 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. An update is available - + アップデートが利用可能です An update to %1 is available. - + %1 のアップデートが利用可能です。 + Do you want to download and install it now? You will need to restart the emulator when the download is complete. - + +今すぐダウンロードしてインストールしますか?ダウンロードが完了したら、エミュレータを再起動する必要があります。 Auto-update is not available on this platform. If you wish to update you will need to do it manually. - + +このプラットフォームでは自動アップデートは利用できません。アップデートしたい場合は手動で行う必要があります。 Current version: %1 New version: %2 Download size: %3 - + 現在のバージョン: %1 +新しいバージョン: %2 +ダウンロードサイズ: %3 Downloading update... - + アップデートをダウンロード中... Downloading failed. Please update manually. - + ダウンロードに失敗しました。手動で更新してください。 Downloading done. Press OK to restart %1 and install the update. - + ダウンロード完了。OKで%1 を再起動し、アップデートをインストールします。 QGBA::ApplicationUpdater - + Stable - - - - - Development - + 安定版 + Development + 開発版 + + + Unknown 不明 - + (None) - + (なし) @@ -170,7 +198,7 @@ Download size: %3 Audio device is missing its core - + オーディオ デバイスにコアがありません @@ -259,28 +287,28 @@ Download size: %3 BattleChip data missing - + バトルチップのデータが見つかりません BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? - + バトルチップの画像データが見つかりません。このままでもチップゲートは動作しますが、チップの画像が表示されないまま使う事になります。今すぐダウンロードしますか? Select deck file - + デッキファイルを選択 Incompatible deck - + 互換性のないデッキ The selected deck is not compatible with this Chip Gate - + 選択したデッキはこのチップゲートでは使用できません @@ -306,7 +334,7 @@ Download size: %3 Add New Code - + 新しいコード @@ -316,12 +344,12 @@ Download size: %3 Add Lines - + 入力したコードを追加 Code type - + コード形式 @@ -342,7 +370,7 @@ Download size: %3 Autodetect (recommended) - + 自動検出 (推奨) @@ -353,54 +381,54 @@ Download size: %3 Some cheats could not be added. Please ensure they're formatted correctly and/or try other cheat types. - + 一部のコードが追加できませんでした。フォーマットが正常かどうかを確認してください。もしくは、違う形式に変換して試してみてください。 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 セーブファイルを開けませんでした: %1 - + Failed to open game file: %1 ゲームファイルを開けませんでした: %1 - + Can't yank pack in unexpected platform! 予期しないプラットフォームでパックをヤンクすることはできません! - + Failed to open snapshot file for reading: %1 読み取り用のスナップショットファイルを開けませんでした: %1 - + Failed to open snapshot file for writing: %1 書き込み用のスナップショットファイルを開けませんでした: %1 @@ -408,17 +436,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 ゲームファイルを開けませんでした: %1 - + Could not load game. Are you sure it's in the correct format? ゲームをロードできませんでした。ゲームのフォーマットが正しいことを確認してください。 - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -444,7 +472,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -489,11 +517,205 @@ Download size: %3 Couldn't Connect - + 接続失敗 Could not connect to Dolphin. + Dolphinと接続できませんでした。 + + + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + バックグラウンド + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + 参照 + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) @@ -535,52 +757,52 @@ Download size: %3 リセット - + Export frame フレームを書き出す - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None なし - + Background バックグラウンド - + Window ウインドウ - + Objwin Objwin - + Sprite スプライト - + Backdrop 背景 - + Frame フレーム - + %1 %2 %1 %2 @@ -588,7 +810,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence DiscordのRich Presence有効 @@ -596,22 +818,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button ボタンクリア - + Clear Analog アナログクリア - + Refresh 更新 - + Set all すべて設定 @@ -745,148 +967,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect 自動検出 - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2764,26 +3006,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - メニュー - QGBA::LibraryTree @@ -2905,7 +3132,7 @@ Download size: %3 破損 - + Slot %1 スロット %1 @@ -3131,39 +3358,39 @@ Download size: %3 ミラー - + None なし - + Both 両方 - + Horizontal - + Vertical - - - + + + N/A N/A - + Export map マップを書き出す - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3305,7 +3532,7 @@ Download size: %3 Width - 値幅 + サイズ @@ -3335,7 +3562,7 @@ Download size: %3 Search type - 検索タイプ + 検索方法 @@ -3355,7 +3582,7 @@ Download size: %3 Unknown/changed - 不明/変更した + 不明/変化した値 @@ -3406,7 +3633,7 @@ Download size: %3 Open in Memory Viewer - メモリービューアーを開く + メモリビューアーを開く @@ -3414,22 +3641,22 @@ Download size: %3 更新 - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 byte%2 @@ -3439,7 +3666,7 @@ Download size: %3 Memory - メモリービューアー + メモリビューアー @@ -3520,6 +3747,24 @@ Download size: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4018,6 +4263,7 @@ Download size: %3 + (unknown) (不明) @@ -4061,6 +4307,11 @@ Download size: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4115,7 +4366,7 @@ Download size: %3 Save games and save states (%1) - ゲームとステートをセーブ(%1) + セーブデータ または ステートセーブ (%1) @@ -4125,27 +4376,27 @@ Download size: %3 Save games (%1) - + セーブデータ (%1) Select save game - + セーブデータを選択 Conversion failed - + 変換に失敗しました Failed to convert the save game. This is probably a bug. - + セーブデータの変換に失敗しました。バグによるものである可能性があります。 No file selected - + ファイルが選択されていません @@ -4160,27 +4411,27 @@ Download size: %3 Please select a valid input file - + 有効な入力ファイルを選択してください No valid conversions found - + 利用可能な変換先がありません - + Cannot convert save games between platforms Convert/Extract Save Game - + セーブデータの変換/抽出 Input file - + 入力 @@ -4191,95 +4442,100 @@ Download size: %3 Output file - + 出力 - + %1 %2 save game - + little endian リトルエンディアン - + big endian ビッグエンディアン - + SRAM SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %2 形式のセーブデータが埋め込まれた %1 のステートセーブ - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4287,7 +4543,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4380,12 +4636,12 @@ Download size: %3 Offset time - + オフセット sec - + @@ -4433,105 +4689,115 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimedia - + SDL SDL - + Software (Qt) ソフト(Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL(バージョン1.xを強制) - + None なし - + None (Still Image) なし(静止画) - + Keyboard キーボード - + Controllers コントローラー - + Shortcuts ショートカット - - + + Shaders シェーダー - + Select BIOS BIOSを選択 - + Select directory - + フォルダを選択 - - (%1×%2) - (%1×%2) + + Select image + 画像を開く - - Never + + Image file (*.png *.jpg *.jpeg) - Just now - + (%1×%2) + (%1×%2) - + + Never + 一度もしていない + + + + Just now + たった今 + + + Less than an hour ago - + 1時間以内 - + %n hour(s) ago - - + + %n 時間前 - + %n day(s) ago - - + + %n 日前 @@ -4547,7 +4813,7 @@ Download size: %3 Gameplay - + ゲームプレイ @@ -4557,7 +4823,7 @@ Download size: %3 Update - + アップデート @@ -4582,7 +4848,7 @@ Download size: %3 Logging - ロギング + ログ @@ -4692,22 +4958,22 @@ Download size: %3 Audio in multiplayer: - + マルチプレイ時に音を出すウィンドウ: All windows - + 全て Player 1 window only - + プレイヤー1のみ Currently active player window - + アクティブなウィンドウ @@ -4726,7 +4992,7 @@ Download size: %3 - + frames フレーム @@ -4770,43 +5036,43 @@ Download size: %3 Show filename instead of ROM name in library view - + ライブラリにゲーム名ではなくファイル名を表示する Pause - + ポーズ When inactive: - + 非アクティブ時: On loading a game: - + ゲーム起動時: Load last state - + 最新のステートセーブを読み込む Load cheats - + チートコードを読み込む Save entered cheats - + 入力されたチートコードを保存する When minimized: - + 最小化時: @@ -4819,84 +5085,94 @@ Download size: %3 - + + Custom border: + + + + Current channel: - + 現在のチャネル: - + Current version: - + 現在のバージョン: - + Update channel: - + 更新チャネル: - + Available version: - + 利用可能なバージョン: - + (Unknown) - + (不明) - + Last checked: - + 最終確認: - + Automatically check on start - + 起動時に自動的に確認する - + Check now + 更新を確認 + + + + Rewind speed: - + Default color palette only - + SGB color palette if available - + GBC color palette if available - + SGB (preferred) or GBC color palette if available - + Game Boy Camera - + Driver: - + Source: Native (59.7275) - ネイティブ (59,7275) + ネイティブ (59.7275) @@ -4914,93 +5190,93 @@ Download size: %3 OSDメッセージを表示 - + Fast forward (held) speed: 早送り(押し)速度: Save state extra data: - + ステートセーブに含める: Periodically autosave state - + 定期的に自動でステートセーブする Save game - + セーブデータ Load state extra data: - + ステートロード時に読み込む: - + Models - + GB only: - + SGB compatible: - + GBC only: - + GBC compatible: - + SGB and GBC compatible: - + Game Boy palette - + Preset: - + Enable Game Boy Player features by default ゲームボーイプレーヤーの機能をデフォルトで有効化 - + (240×160) (240×160) - + Log to file - ファイル出力 + ファイルに出力する - + Log to console - コンソール出力 + コンソールに出力する - + Select Log File ログファイルを選択 @@ -5065,43 +5341,43 @@ Download size: %3 タイトルバーにゲーム名の代わりにファイル名を表示 - + Fast forward speed: 早送り速度: - - + + Unbounded 制限なし - + Enable rewind 巻戻し有効 - + Rewind history: 巻戻し履歴: - + Idle loops: アイドルループ: - + Run all すべて実行 - + Remove known 既知を削除 - + Detect and remove 検出して削除 @@ -5118,139 +5394,140 @@ Download size: %3 チートコード - + Preload entire ROM into memory ROM全体をメモリにプリロード - + Autofire interval: 連射間隔: - + Enable VBA bug compatibility in ROM hacks - + Video renderer: ビデオレンダラー: - + Software ソフト - + OpenGL enhancements OpenGL機能強化 - + High-resolution scale: 高解像度スケール: - + XQ GBA audio (experimental) XQ GBA オーディオ機能(実験的) - + GB BIOS file: - ゲームボーイBIOS: + ゲームボーイ: - - - - - - - - - + + + + + + + + + + Browse 参照 - + Use BIOS file if found 存在する場合にBIOSファイルを使用 - + Skip BIOS intro BIOSイントロをスキップ - + GBA BIOS file: - ゲームボーイアドバンスBIOS: + ゲームボーイアドバンス: - + GBC BIOS file: - ゲームボーイカラーBIOS: + ゲームボーイカラー: - + SGB BIOS file: - スーパーゲームボーイBIOS: + スーパーゲームボーイ: - + Save games セーブデータ - - - - - + + + + + Same directory as the ROM ROMファイルと同じディレクトリ - + Save states セーブステート - + Screenshots スクリーンショット - + Patches パッチ - + Cheats チート - + Default BG colors: デフォルト背景色: - + Super Game Boy borders スーパーゲームボーイのボーダー - + Default sprite colors 1: デフォルトスプライト1: - + Default sprite colors 2: デフォルトスプライト2: @@ -5263,27 +5540,28 @@ Download size: %3 アクティブなシェーダーがありません - + + Load shader シェーダーをロード - + No shader loaded シェーダーがロードされていません - + by %1 by %1 - + Preprocessing 前処理中 - + Pass %1 Pass %1 @@ -5326,17 +5604,17 @@ Download size: %3 QGBA::ShortcutModel - + Action アクション - + Keyboard キーボード - + Gamepad ゲームパッド @@ -5456,17 +5734,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 出力ビデオファイルを開けませんでした: %1 - + Native (%0x%1) ネイティブ(%0x%1) - + Select output file 出力ファイルを選択 @@ -5677,100 +5955,80 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - ゲームボーイアドバンスファイル (%1) - - - - Game Boy ROMs (%1) - ゲームボーイファイル (%1) - - - - All ROMs (%1) - すべてのファイル (%1) - - - - %1 Video Logs (*.mvl) - %1ビデオログ (*.mvl) - - - + Archives (%1) アーカイブファイル (%1) - - - + + + Select ROM ROMを開く - + Select folder フォルダを開く - - + + Select save セーブを開く - + Select patch パッチを開く - + Patches (*.ips *.ups *.bps) パッチファイル (*.ips *.ups *.bps) - + Select e-Reader dotcode カードeを開く - + e-Reader card (*.raw *.bin *.bmp) カードe (*.raw *.bin *.bmp) - + Select image 画像を開く - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) 画像ファイル (*.png *.gif *.jpg *.jpeg);;すべてのファイル (*) - + GameShark saves (*.sps *.xps) GameSharkセーブファイル (*.sps *.xps) - + Select video log ビデオログを開く - + Video logs (*.mvl) ビデオログ (*.mvl) - + Crash クラッシュ - + The game has crashed with the following error: %1 @@ -5779,684 +6037,699 @@ Download size: %3 %1 - + Couldn't Start 起動失敗 - + Could not start game. ゲームを起動できませんでした。 - + Unimplemented BIOS call 未実装のBIOS呼び出し - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. このゲームは実装されていないBIOS呼び出しを使用します。最高のエクスペリエンスを得るには公式のBIOSを使用してください。 - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. 適切なディスプレイデバイスの作成に失敗し、ソフトディスプレイにフォールバックしました。特に大きなウィンドウでは、ゲームの実行が遅い場合があります。 - + Really make portable? - 本当にポータブルにしますか? + 本当にポータブル化しますか? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - これによりエミュレータは実行ファイルと同じディレクトリにある設定ファイルをロードします。続けますか? + ポータブル化すると、以降は実行ファイルと同じディレクトリに設定ファイルが置かれるようになります。続行しますか? - + Restart needed 再起動が必要 - + Some changes will not take effect until the emulator is restarted. 一部の変更は、エミュレータを再起動するまで有効になりません。 - + - Player %1 of %2 - プレーヤー %1 of %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File &ファイル (&F) - + Load &ROM... ROMをロード... - + Load ROM in archive... アーカイブにROMをロード... - + Add folder to library... ライブラリーにフォルダを追加... - + Load &patch... パッチをロード... (&P) - + Boot BIOS BIOSを起動 - + Replace ROM... ROMを交換... - + Scan e-Reader dotcodes... カードeをスキャン... - + ROM &info... ROM情報... (&I) - + Recent 最近開いたROM - + Make portable ポータブル化 - + &Load state ステートをロード (&L) - + Report bug... バグ報告 - + About... バージョン情報... - + Record GIF/WebP/APNG... GIF/WebP/APNGを記録 - + Game Pak sensors... カートリッジセンサー... - + Clear 消去 - + Load state file... ステートファイルをロード... - + Save games (%1) - + セーブデータ (%1) - + Select save game - + セーブデータを選択 - + mGBA save state files (%1) - - + + Select save state - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Load alternate save game... - + Load temporary save game... - + Convert e-Reader card image to raw... - + &Save state ステートをセーブ (&S) - + Save state file... ステートファイルをセーブ... - + Quick load クイックロード - + Quick save クイックセーブ - + Load recent - 最近使ったクイックロットからロード + 最後に使ったクイックスロットからロード - + Save recent - 最近使ったクイックロットにセーブ + 最後に使ったクイックスロットにセーブ - + Undo load state クイックロードを元に戻す - + Undo save state クイックセーブを元に戻す - - + + State &%1 クイックスロット &%1 - + Load camera image... カメラ画像をロード... - + Convert save game... - + セーブデータを変換... - + GameShark saves (*.gsv *.sps *.xps) - + Import GameShark Save... GameSharkスナップショットを読み込む - + Export GameShark Save... GameSharkスナップショットを書き出す - + New multiplayer window 新しいウィンドウ(マルチプレイ) - + Connect to Dolphin... - + Dolphinに接続... - + E&xit 終了 (&X) - + &Emulation エミュレーション (&E) - + &Reset リセット (&R) - + Sh&utdown 閉じる (&U) - + Yank game pak - ゲームパックをヤンク + カートリッジを抜く - + &Pause 一時停止 (&P) - + &Next frame 次のフレーム (&N) - + Fast forward (held) 早送り(押し) - + &Fast forward 早送り (&F) - + Fast forward speed 早送り速度 - + Unbounded 制限なし - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) 巻戻し(押し) - + Re&wind 巻戻し (&R) - + Step backwards 1フレーム巻き戻す - + Solar sensor 太陽センサー - + Increase solar level 明るさを上げる - + Decrease solar level 明るさを下げる - + Brightest solar level 明るさ最高 - + Darkest solar level 明るさ最低 - + Brightness %1 明るさ %1 - + Audio/&Video オーディオ/ビデオ (&V) - + Frame size 画面サイズ - + Toggle fullscreen 全画面表示 - + Lock aspect ratio 縦横比を固定 - + Force integer scaling 整数スケーリングを強制 - + Bilinear filtering バイリニアフィルタリング - + Frame&skip フレームスキップ (&S) - + Mute ミュート - + FPS target FPS - + Native (59.7275) ネイティブ(59.7275) - + Take &screenshot スクリーンショット (&S) - + F12 F12 - + Game Boy Printer... ポケットプリンタ... - + Reset needed - + Some changes will not take effect until the game is reset. - + Save games セーブデータ - + Automatically determine - + Use player %0 save game - + BattleChip Gate... - チップゲート... + バトルチップゲート... - + %1× %1× - + Interframe blending フレーム間混合 - + Record A/V... ビデオ録画... - + Video layers ビデオレイヤー - + Audio channels オーディオチャンネル - + Adjust layer placement... レイヤーの配置を調整... - + &Tools ツール (&T) - + View &logs... ログビューアー... (&L) - + Game &overrides... ゲーム別設定... (&O) - + &Cheats... チート... (&C) - + Settings... 設定... - + Open debugger console... デバッガコンソールを開く... - + Start &GDB server... GDBサーバを起動... (&G) - + Scripting... - - Game state views + + Create forwarder... + Game state views + + + + View &palette... パレットビューアー... (&P) - + View &sprites... スプライトビューアー... (&S) - + View &tiles... タイルビューアー... (&T) - + View &map... マップビューアー... (&M) - + &Frame inspector... フレームインスペクタ... (&F) - + View memory... メモリビューアー... - + Search memory... メモリ検索... - + View &I/O registers... IOビューアー... (&I) - + Record debug video log... デバッグビデオログ... - + Stop debug video log デバッグビデオログを停止 - + Exit fullscreen 全画面表示を終了 - + GameShark Button (held) GameSharkボタン(押し) - + Autofire 連打 - + Autofire A 連打 A - + Autofire B 連打 B - + Autofire L 連打 L - + Autofire R 連打 R - + Autofire Start 連打 Start - + Autofire Select 連打 Select - + Autofire Up 連打 上 - + Autofire Right 連打 右 - + Autofire Down 連打 下 - + Autofire Left 連打 左 @@ -6464,55 +6737,70 @@ Download size: %3 QObject - + %1 byte - + %1 kiB - + %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + メニュー + QShortcut - + Shift Shift - + Control Control - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/ts/mgba-ko.ts b/src/platform/qt/ts/mgba-ko.ts index 4f47fe85e..a0955e500 100644 --- a/src/platform/qt/ts/mgba-ko.ts +++ b/src/platform/qt/ts/mgba-ko.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + 게임보이 어드밴스 롬 (%1) + + + + Game Boy ROMs (%1) + 게임보이 롬 (%1) + + + + All ROMs (%1) + 모든 롬 (%1) + + + + %1 Video Logs (*.mvl) + %1 비디오 로그 (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable 안정적인 - + Development 개발 - + Unknown 미확인 - + (None) (없음) @@ -364,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 r%1-%2 %3 재설정 - - + + Rewinding not currently enabled 현재 활성화되지 않은 되감기 - + Reset the game? 게임을 재설정하겠습니까? - + Most games will require a reset to load the new save. Do you want to reset now? 대부분의 게임은 새로운 저장을 로드하려면 재설정이 필요합니다. 지금 재설정하겠습니까? - + Failed to open save file: %1 저장 파일을 열지 못했습니다: %1 - + Failed to open game file: %1 게임 파일을 열지 못했습니다: %1 - + Can't yank pack in unexpected platform! 예기치 않은 플랫폼에서 팩을 잡아당길 수 없습니다! - + Failed to open snapshot file for reading: %1 읽기 용 스냅샷 파일을 열지 못했습니다: %1 - + Failed to open snapshot file for writing: %1 쓰기 용 스냅샷 파일을 열지 못했습니다: %1 @@ -413,17 +436,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 게임 파일을 열지 못했습니다: %1 - + Could not load game. Are you sure it's in the correct format? 게임을 로드할 수 없습니다. 올바른 형식인지 확인했나요? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). 저장 파일을 열지 못했습니다. 게임 내 저장은 업데이트할 수 없습니다. 저장 디렉토리가 추가 권한 없이 쓰기 가능한지 확인하세요 (예: 윈도우즈의 UAC). @@ -449,7 +472,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing 쓰기 위해 CLI 기록을 열 수 없음 @@ -502,6 +525,200 @@ Download size: %3 돌핀에 연결할 수 없습니다. + + QGBA::ForwarderGenerator + + + 3DS + 3DS + + + + Vita + 비타 + + + + QGBA::ForwarderGenerator3DS + + + Icon + 아이콘 + + + + Banner + 배너 + + + + QGBA::ForwarderGeneratorVita + + + Bubble + 거품 + + + + Background + 배경 + + + + Startup + 시작 + + + + QGBA::ForwarderView + + + Create forwarder + 포워더 생성 + + + + Files + 파일 + + + + ROM file: + 롬 파일: + + + + + + Browse + 찾아보기 + + + + Output filename: + 출력 파일이름: + + + + Forwarder base: + 포워더 기반: + + + + Latest stable version + 최신 안정 버전 + + + + Latest development build + 최신 개발 빌드 + + + + Specific file + 특정 파일 + + + + Base file: + 기본 파일: + + + + System + 시스템 + + + + 3DS + 3DS + + + + Vita + 비타 + + + + Presentation + 프레젠테이션 + + + + Title: + 타이틀: + + + + Images: + 이미지: + + + + Use default image + 기본 이미지 사용 + + + + Preferred size: + 선호하는 크기: + + + + Select image file + 이미지 파일 선택 + + + + Select ROM file + 롬 파일 선택 + + + + Select output filename + 출력 파일이름 선택 + + + + Select base file + 기본 파일 선택 + + + + Build finished + 빌드 완료 + + + + Forwarder finished building + 포워더 완료된 빌드 + + + + Build failed + 빌드 실패 + + + + Failed to build forwarder + 포워더 빌드 실패 + + + + %1 installable package (*.%2) + %1 설치 가능한 패키지 (*.%2) + + + + Select an image + 이미지 선택 + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Download size: %3 재설정 - + Export frame 프레임 내보내기 - + Portable Network Graphics (*.png) 휴대용 네트워크 그래픽 (*.png) - + None 없음 - + Background 배경 - + Window - + Objwin Objwin - + Sprite 스프라이트 - + Backdrop 배경 - + Frame 프레임 - + %1 %2 %1 %2 @@ -593,7 +810,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence 디스코드 Rich Presence 활성화 @@ -601,22 +818,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button 버튼 정리 - + Clear Analog 아날로그 정리 - + Refresh 새로 고침 - + Set all 모두 설정 @@ -750,148 +967,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect 자동 감지 - + Game Boy (DMG) 게임 보이 (DMG) - + Game Boy Pocket (MGB) 게임 보이 포켓 (MGB) - + Super Game Boy (SGB) 슈퍼 게임 보이 (SGB) - + Super Game Boy 2 (SGB) 슈퍼 게임 보이 2 (SGB) - + Game Boy Color (CGB) 게임 보이 컬러 (CGB) - + Game Boy Advance (AGB) 게임 보이 어드밴스 (AGB) - + Super Game Boy Color (SGB + CGB) 슈퍼 게임 보이 컬러 (SGB + CGB) - + ROM Only 롬 전용 - + MBC1 MBC1 - + MBC2 MBC2 - + MBC3 MBC3 - + MBC3 + RTC MBC3 + RTC - + MBC5 MBC5 - + MBC5 + Rumble MBC5 + 진동 - + MBC6 MBC6 - + MBC7 (Tilt) MBC7 (틸트) - + MMM01 MMM01 - + HuC-1 HuC-1 - + HuC-3 HuC-3 - + Pocket Cam 포켓 캠 - + TAMA5 TAMA5 - + Wisdom Tree 지혜의 나무 - + + NT (old 1) + NT (이전 1) + + + + NT (old 2) + NT (이전 2) + + + NT (new) NT (신규) - + Pokémon Jade/Diamond 포켓몬 제이드/다이아몬드 - + BBD BBD - + Hitek 하이텍 - + + GGB-81 + GGB-81 + + + + Li Cheng + Li Cheng + + + Sachen (MMC1) 사첸 (MMC1) - + Sachen (MMC2) 사첸 (MMC2) @@ -2769,26 +3006,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - 슈퍼 (L) - - - - Super (R) - 슈퍼 (R) - - - - Menu - 메뉴 - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Download size: %3 손상 - + Slot %1 슬롯 %1 @@ -3136,39 +3358,39 @@ Download size: %3 미러링 - + None 없음 - + Both 둘 다 - + Horizontal 수평 - + Vertical 수직 - - - + + + N/A 해당 없음 - + Export map 맵 내보내기 - + Portable Network Graphics (*.png) 휴대용 네트워크 그래픽 (*.png) @@ -3419,22 +3641,22 @@ Download size: %3 새로 고침 - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 바이트%2 @@ -3525,6 +3747,24 @@ Download size: %3 %1 프레임 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4023,6 +4263,7 @@ Download size: %3 + (unknown) (미확인) @@ -4066,6 +4307,11 @@ Download size: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4173,7 +4419,7 @@ Download size: %3 유효한 전환 없음 - + Cannot convert save games between platforms 플랫폼 간에 저장 게임 변환할 수 없음 @@ -4199,92 +4445,97 @@ Download size: %3 출력 파일 - + %1 %2 save game %1 %2 저장 게임 - + little endian 리틀 엔디안 - + big endian 빅 엔디안 - + SRAM SRAM - + %1 flash %1 플래시 - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 팩킹된 MBC2 - + unpacked MBC2 언팩킹된 MBC2 - + MBC6 flash MBC6 플래시 - + MBC6 combined SRAM + flash MBC6 결합 SRAM + 플래시 - + MBC6 SRAM MBC6 SRAM - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game 포함된 %2 저장 게임이 있는 %1 저장 상태 - + %1 SharkPort %2 save game %1 샤크포트 %2 게임 저장 - + %1 GameShark Advance SP %2 save game %1 게임샤크 어드밴스 SP %2 게임 저장 @@ -4292,7 +4543,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer 제목 없는 버퍼 @@ -4438,102 +4689,112 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia Qt 멀티미디어 - + SDL SDL - + Software (Qt) 소프트웨어 (Qt) - - + + OpenGL 오픈GL - + OpenGL (force version 1.x) 오픈GL (버전 1.x 강제) - + None 없음 - + None (Still Image) 없음 (정지 이미지) - + Keyboard 키보드 - + Controllers 컨트롤러 - + Shortcuts 단축키 - - + + Shaders 쉐이더 - + Select BIOS 바이오스 선택 - + Select directory 디렉토리 선택 - + + Select image + 이미지 선택 + + + + Image file (*.png *.jpg *.jpeg) + 이미지 파일 (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never 절대 - + Just now 방금 - + Less than an hour ago 1시간 미만 전 - + %n hour(s) ago %n 시간 전 - + %n day(s) ago %n 일 전 @@ -4726,7 +4987,7 @@ Download size: %3 - + frames 프레임 @@ -4804,77 +5065,87 @@ Download size: %3 최소화할 때: - + + Custom border: + + + + Current channel: 현재 채널: - + Current version: 현재 버전: - + Update channel: 업데이트 채널: - + Available version: 사용 가능한 버전: - + (Unknown) (알 수 없음) - + Last checked: 마지막 확인: - + Automatically check on start 시작 시 자동으로 확인 - + Check now 지금 확인 - + + Rewind speed: + + + + Default color palette only 기본 색상 팔레트만 - + SGB color palette if available 가능한 경우 SGB 색상 팔레트 - + GBC color palette if available 가능한 경우 GBC 색상 팔레트 - + SGB (preferred) or GBC color palette if available 사용 가능한 경우 SGB (선호) 또는 GBC 색상 팔레트 - + Game Boy Camera 게임 보이 카메라 - + Driver: 드라이버: - + Source: 소스: @@ -4919,7 +5190,7 @@ Download size: %3 디스코드 Rich Presence 활성화 - + Fast forward (held) speed: 빨리 감기 (고정) 속도: @@ -4945,122 +5216,122 @@ Download size: %3 상태 추가 데이터 로드: - + Models 모델 - + GB only: GB 전용: - + SGB compatible: SGB 호환: - + GBC only: GBC 전용: - + GBC compatible: GBC 호환: - + SGB and GBC compatible: SGB 와 GBC 호환: - + Game Boy palette 게임 보이 팔레트 - + Preset: 사전 설정: - + Enable Game Boy Player features by default 기본적으로 게임 보이 플레이어 기능 활성화 - + Enable VBA bug compatibility in ROM hacks 롬 해킹에서 VBA 버그 호환성 활성화 - + Video renderer: 비디오 렌더러: - + Software 소프트웨어 - + OpenGL enhancements OpenGL 개선 사항 - + High-resolution scale: 고해상도 스케일: - + (240×160) (240×160) - + XQ GBA audio (experimental) XQ GBA 오디오 (시험용) - + Cheats 치트 - + Default BG colors: 기본 배경 색상: - + Super Game Boy borders 슈퍼 게임 보이 테두리 - + Default sprite colors 1: 기본 스프라이트 색상 1: - + Log to file 파일에 기록 - + Log to console 콘솔에 기록 - + Select Log File 로그 파일 선택 - + Default sprite colors 2: 기본 스프라이트 색상 2: @@ -5080,36 +5351,37 @@ Download size: %3 캐시 지우기 - + Fast forward speed: 빨리 감기 속도: - - - - - - - - - + + + + + + + + + + Browse 브라우저 - + Use BIOS file if found 발견되면 바이오스 파일 사용 - + Skip BIOS intro 바이오스 소개 건너 뛰기 - - + + Unbounded 무제한 @@ -5124,17 +5396,17 @@ Download size: %3 바이오스 - + Run all 모두 실행 - + Remove known 알려진 것 제거 - + Detect and remove 감지 및 제거 @@ -5156,7 +5428,7 @@ Download size: %3 치트 코드 - + Enable rewind Abilita riavvolgimento @@ -5191,71 +5463,71 @@ Download size: %3 제목 표시 줄에 FPS 표시 - + Rewind history: 되감기 기록: - + Idle loops: 유휴 루프: - + Preload entire ROM into memory 전체 ROM을 메모리에 미리 로드 - + Autofire interval: Intervallo Autofire: - + GB BIOS file: GB 바이오스 파일: - + GBA BIOS file: GBA 바이오스 파일: - + GBC BIOS file: GBC 바이오스 파일: - + SGB BIOS file: SGB 바이오스 파일: - + Save games 게임 저장 - - - - - + + + + + Same directory as the ROM 롬과 같은 디렉토리 - + Save states 저장 파일 상태 - + Screenshots 스크린샷 - + Patches 패치 @@ -5268,27 +5540,28 @@ Download size: %3 활성 셰이더 없음 - + + Load shader 쉐이더 로드 - + No shader loaded 로드된 쉐이더 없음 - + by %1 %1에 의해 - + Preprocessing 전처리 - + Pass %1 %1 패스 @@ -5331,17 +5604,17 @@ Download size: %3 QGBA::ShortcutModel - + Action 동작 - + Keyboard 키보드 - + Gamepad 게임패드 @@ -5461,17 +5734,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 출력 비디오 파일을 열지 못했습니다: %1 - + Native (%0x%1) 기본 (%0x%1) - + Select output file 출력 파일 선택 @@ -5616,7 +5889,7 @@ Download size: %3 WavPack - + Wav팩 @@ -5682,115 +5955,95 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - 게임 보이 어드밴스 롬 (%1) - - - - Game Boy ROMs (%1) - 게임 보이 (%1) - - - - All ROMs (%1) - 모든 롬 (%1) - - - - %1 Video Logs (*.mvl) - %1 비디오 로그 (*.mvl) - - - + Archives (%1) 아카이브 (%1) - - - + + + Select ROM 롬 선택 - - + + Select save 저장 파일 선택 - + Select patch 패치 선택 - + Patches (*.ips *.ups *.bps) 패치 (*.ips *.ups *.bps) - + Select e-Reader dotcode e-리더 도트코드 선택 - + e-Reader card (*.raw *.bin *.bmp) e-리더 카드 (*.raw *.bin *.bmp) - + Select e-Reader card images e-리더 카드 이미지 선택 - + Image file (*.png *.jpg *.jpeg) 이미지 파일 (*.png *.jpg *.jpeg) - + Conversion finished 변환 완료 - + %1 of %2 e-Reader cards converted successfully. %2 e-리더 카드 중 %1이(가) 성공적으로 변환되었습니다. - + Select image 이미지 선택 - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) 이미지 파일 (*.png *.gif *.jpg *.jpeg);;모든 파일 (*) - + GameShark saves (*.sps *.xps) 게임샤크 저장 파일 (*.sps *.xps) - + Select video log 비디오 로그 선택 - + Video logs (*.mvl) 비디오 로그 (*.mvl) - + Crash 치명적인 오류 - + The game has crashed with the following error: %1 @@ -5799,669 +6052,684 @@ Download size: %3 %1 - + Unimplemented BIOS call 구현되지 않은 바이오스 호출 - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. 이 게임은 구현되지 않은 바이오스 호출을 사용합니다. 최상의 성능을 얻으려면 공식 바이오스를 사용하십시오. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. 적절한 디스플레이 장치를 생성하지 못했습니다. 소프트웨어 디스플레이로 돌아갑니다. 특히 큰 창에서는 게임이 느리게 실행될 수 있습니다. - + Really make portable? 정말로 휴대용을 만듭니까? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? 이렇게하면 에뮬레이터가 실행 파일과 동일한 디렉토리에서 구성을 로드하게됩니다. 계속 하시겠습니까? - + Restart needed 재시작 필요 - + Some changes will not take effect until the emulator is restarted. 일부 변경 사항은 에뮬레이터가 다시 시작될 때까지 적용되지 않습니다. - + Reset needed 재설정 필요 - + Some changes will not take effect until the game is reset. 일부 변경 사항은 게임이 재설정될 때까지 적용되지 않습니다. - + - Player %1 of %2 - 플레이어 %1 의 %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File &파일 - + Load &ROM... 로드 &롬... - + Load ROM in archive... 롬을 아카이브에 로드... - + Save games 게임 저장 - + Automatically determine 자동으로 결정 - + Use player %0 save game 플레이어 %0 저장 게임 사용 - + Load &patch... 로드 &패치... - + Boot BIOS BIOS 부팅 - + Replace ROM... 롬 교체... - + Scan e-Reader dotcodes... e-리더 도트코드 스캔... - + Game state views 게임 상태 보기 - + Convert e-Reader card image to raw... e-리더 카드 이미지를 원시 데이터로 변환... - + ROM &info... 롬 &정보... - + Recent 최근 실행 - + Make portable 휴대용 만들기 - + &Load state &로드 파일 상태 - + &Save state &저장 파일 상태 - + Quick load 빠른 로드 - + Quick save 빠른 저장 - + Load recent 최근 실행 로드 - + Save recent 최근 실행 저장 - + Undo load state 로드 파일 상태 복원 - + Undo save state 저장 파일 상태 복원 - - + + State &%1 상태 &%1 - + Load camera image... 카메라 이미지 로드... - + Convert save game... 저장 게임 변환... - + GameShark saves (*.gsv *.sps *.xps) 게임샤크 저장 (*.gsv *.sps *.xps) - + New multiplayer window 새로운 멀티 플레이어 창 - + Connect to Dolphin... 돌핀에 연결... - + E&xit 종&료 - + &Emulation &에뮬레이션 - + &Reset &재설정 - + Sh&utdown 종&료 - + Yank game pak 양키 게임 팩 - + &Pause &정지 - + &Next frame &다음 프레임 - + Fast forward (held) 빨리 감기 (누름) - + &Fast forward &빨리 감기 - + Fast forward speed 빨리 감기 속도 - + Unbounded 무제한 - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) 되김기 (누름) - + Re&wind 리&와인드 - + Step backwards 돌아가기 - + Brightest solar level 가장 밝은 태양 수준 - + Darkest solar level 가장 어두운 태양 수준 - + Brightness %1 밝기 %1 - + Audio/&Video 오디오/&비디오 - + Frame size 프레임 크기 - + Toggle fullscreen 전체화면 전환 - + Lock aspect ratio 화면비 잠금 - + Frame&skip 프레임&건너뛰기 - + Mute 무음 - + FPS target FPS 대상 - + Take &screenshot 스크린샷 &찍기 - + F12 F12 - + Video layers 비디오 레이어 - + Audio channels 오디오 채널 - + &Tools &도구 - + View &logs... 로그 &보기... - + Game &overrides... 게임 &오버라이드... - + &Cheats... &치트.. - + + Create forwarder... + 전달자 생성... + + + Open debugger console... 디버거 콘솔 열기... - + Start &GDB server... GDB 서버 &시작... - + Settings... 설정... - + Select folder 폴더 선택 - + Couldn't Start 시작할 수 없음 - + Could not start game. 게임을 시작할 수 없습니다. - + Add folder to library... 라이브러리에 폴더 추가... - + Load state file... 상태 파일 로드... - + Save state file... 상태 파일 저장... - + Import GameShark Save... 게임샤크 저장 가져오기... - + Export GameShark Save... 게임샤크 저장 내보내기... - + Report bug... 버그를 제보하기... - + About... 정보... - + Solar sensor 태양광 센서 - + Increase solar level 태양광 레벨 증가 - + Decrease solar level 태양광 레벨 감소 - + Force integer scaling 정수 스케일링 강제 수행 - + Bilinear filtering 이중선형 필터링 - + Game Boy Printer... 게임 보이 프린터... - + Save games (%1) 게임 (%1) 저장 - + Select save game 저장 게임 선택 - + mGBA save state files (%1) mGBA 저장 상태 파일 (%1) - - + + Select save state 저장 상태 선택 - + Load alternate save game... 대체 저장 게임 로드... - + Load temporary save game... 임시 저장 게임 로드... - + BattleChip Gate... 배틀칩 게이트... - + %1× %1× - + Interframe blending 프레임간 조합 - + Native (59.7275) 실기 (59.7275) - + Record A/V... A/V 녹화... - + Record GIF/WebP/APNG... GIF/WebP/APNG 녹화... - + Adjust layer placement... 레이어 배치 조정... - + Game Pak sensors... 게임 팩 센서... - + Scripting... 스크립팅... - + View &palette... 팔레트 &보기... - + View &sprites... 스프라이트 &보기... - + View &tiles... 타일 &보기... - + View &map... 지도 &보기... - + &Frame inspector... 프레임 검사기 (&F)... - + View memory... 메모리 보기... - + Search memory... 메모리 검색... - + View &I/O registers... I/O 레지스터 &보기... - + Record debug video log... 디버그 비디오 로그 녹화... - + Stop debug video log 디버그 비디오 로그 중지 - + Exit fullscreen 전체화면 종료 - + GameShark Button (held) 게임샤크 버튼 (누름) - + Autofire 연사 - + Autofire A 연사 A - + Autofire B 연사 B - + Autofire L 연사 L - + Autofire R 연사 R - + Autofire Start 연사 시작 - + Autofire Select 연사 선택 - + Clear 지움 - + Autofire Up 연사 위쪽 - + Autofire Right 연사 오른쪽 - + Autofire Down 연사 아래쪽 - + Autofire Left 연사 왼쪽 @@ -6469,55 +6737,70 @@ Download size: %3 QObject - + %1 byte %1 바이트 - + %1 kiB %1 키비바이트 - + %1 MiB %1 메비바이트 - + GBA GBA - + GB GB - + ? ? + + + Super (L) + 슈퍼 (L) + + + + Super (R) + 슈퍼 (R) + + + + Menu + 메뉴 + QShortcut - + Shift 시프트 키 - + Control 콘트롤 키 - + Alt 알트 키 - + Meta 메타 diff --git a/src/platform/qt/ts/mgba-ms.ts b/src/platform/qt/ts/mgba-ms.ts index 54a273a64..cb327e334 100644 --- a/src/platform/qt/ts/mgba-ms.ts +++ b/src/platform/qt/ts/mgba-ms.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ROM Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROM Game Boy (%1) + + + + All ROMs (%1) + Semua ROM (%1) + + + + %1 Video Logs (*.mvl) + %1 Log Video (*.mvl) + + QGBA::AboutScreen @@ -86,22 +109,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable - + Development - + Unknown - + (None) @@ -358,48 +381,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 Gagal membuka fail tersimpan: %1 - + Failed to open game file: %1 Gagal membuka fail permainan: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 Gagal membuka fail snapshot untuk baca: %1 - + Failed to open snapshot file for writing: %1 Gagal membuka fail snapshot untuk menulis: %1 @@ -407,17 +430,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 Gagal membuka fail permainan: %1 - + Could not load game. Are you sure it's in the correct format? Gagal memuat permainan. Adakah ia dalam format betul? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -443,7 +466,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -496,6 +519,200 @@ Download size: %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + Latar belakang + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + Pilih fail + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -534,52 +751,52 @@ Download size: %3 Tetap semula - + Export frame Eksport bingkai - + Portable Network Graphics (*.png) Grafik Rangkaian Mudah Alih (*.png) - + None Tiada - + Background Latar belakang - + Window Tetingkap - + Objwin Objwin - + Sprite - + Backdrop - + Frame Bingkai - + %1 %2 %1 %2 @@ -587,7 +804,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence Dayakan Discord Rich Presence @@ -595,22 +812,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button - + Clear Analog - + Refresh Segar Semula - + Set all @@ -744,148 +961,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect Autokesan - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2763,26 +3000,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - Menu - QGBA::LibraryTree @@ -2904,7 +3126,7 @@ Download size: %3 Rosak - + Slot %1 Slot %1 @@ -3130,39 +3352,39 @@ Download size: %3 Cermin - + None Tiada - + Both - + Horizontal - + Vertical - - - + + + N/A - + Export map Eksport peta - + Portable Network Graphics (*.png) Grafik Rangkaian Mudah Alih (*.png) @@ -3413,22 +3635,22 @@ Download size: %3 Segar Semula - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 bait%2 @@ -3519,6 +3741,24 @@ Download size: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4017,6 +4257,7 @@ Download size: %3 + (unknown) (tidak diketahui) @@ -4060,6 +4301,11 @@ Download size: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4167,7 +4413,7 @@ Download size: %3 Tiada penukaran yang sah ditemui - + Cannot convert save games between platforms Tidak boleh menukar simpanan permainan antara platform @@ -4193,92 +4439,97 @@ Download size: %3 Fail output - + %1 %2 save game Simpanan permainan %1 %2 - + little endian little-endian - + big endian big-endian - + SRAM SRAM - + %1 flash %1 kilat - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash Kilat MBC6 - + MBC6 combined SRAM + flash MBC6 bergabung SRAM + kilat - + MBC6 SRAM SRAM MBC6 - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game Keadaan tersimpan %1 dgn simpanan permainan terbenam %2 - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4286,7 +4537,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4432,102 +4683,112 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia Multimedia Qt - + SDL SDL - + Software (Qt) Perisian (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (paksa versi 1.x) - + None Tiada - + None (Still Image) Tiada (Gambar Tenang) - + Keyboard Papan Kekunci - + Controllers Pengawal - + Shortcuts Pintas - - + + Shaders - + Select BIOS Pilih BIOS - + Select directory Pilih direktori - + + Select image + Pilih gambar + + + + Image file (*.png *.jpg *.jpeg) + Fail gambar (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never - + Just now - + Less than an hour ago - + %n hour(s) ago - + %n day(s) ago @@ -4725,7 +4986,7 @@ Download size: %3 - + frames bingkai @@ -4813,77 +5074,77 @@ Download size: %3 - + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now - + Default color palette only Palet warna piawai sahaja - + SGB color palette if available Palet warna SGB jika ada - + GBC color palette if available Palet warna GBC jika ada - + SGB (preferred) or GBC color palette if available SGB (pilihan utama) atau palet warna GBC jika ada - + Game Boy Camera Game Boy Camera - + Driver: Pemacu: - + Source: Sumber: @@ -4978,58 +5239,68 @@ Download size: %3 - + + Custom border: + + + + Fast forward speed: Kelajuan mundar laju: - - + + Unbounded Tidak terbatas - + Fast forward (held) speed: Kelajuan mundar laju (pegang): - + Autofire interval: - + Enable rewind Dayakan putar balik - + Rewind history: Sejarah putar balik: - + + Rewind speed: + + + + Idle loops: - + Run all Jalan semua - + Remove known Buang yg diketahui - + Detect and remove Kesan dan buang - + Preload entire ROM into memory Pra-muat selurus ROM ke dalam ingatan @@ -5050,42 +5321,42 @@ Download size: %3 Data ekstra keadaan muat: - + Models Model - + GB only: GB sahaja: - + SGB compatible: SGB serasi: - + GBC only: GBC sahaja: - + GBC compatible: GBC serasi: - + SGB and GBC compatible: SGB dan GBC serasi: - + Game Boy palette Palet Game Boy - + Preset: Praset: @@ -5102,154 +5373,155 @@ Download size: %3 Kod tipu - + Enable Game Boy Player features by default - + Enable VBA bug compatibility in ROM hacks - + Video renderer: - + Software Perisian - + OpenGL enhancements - + High-resolution scale: - + (240×160) (240×160) - + XQ GBA audio (experimental) - + GB BIOS file: Fail BIOS GB: - - - - - - - - - + + + + + + + + + + Browse Pilih fail - + Use BIOS file if found Guna fail BIOS jika ada - + Skip BIOS intro Langkau pendahuluan BIOS - + GBA BIOS file: Fail BIOS GBA: - + GBC BIOS file: Fail BIOS GBC: - + SGB BIOS file: Fail BIOS SGB: - + Save games Simpanan permainan - - - - - + + + + + Same directory as the ROM Direktori sama dengan ROM - + Save states Keadaan tersimpan - + Screenshots Cekupan skrin - + Patches - + Cheats Tipuan - + Log to file Log dalam fail - + Log to console Log dalam konsol - + Select Log File Pilih fail log - + Default BG colors: Warna LB piawai: - + Default sprite colors 1: - + Default sprite colors 2: - + Super Game Boy borders @@ -5262,27 +5534,28 @@ Download size: %3 - + + Load shader - + No shader loaded - + by %1 - + Preprocessing - + Pass %1 @@ -5325,17 +5598,17 @@ Download size: %3 QGBA::ShortcutModel - + Action - + Keyboard - + Gamepad @@ -5455,17 +5728,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 Gagal membuka fail video output: %1 - + Native (%0x%1) Asal (%0x%1) - + Select output file Pilih fail output @@ -5676,100 +5949,80 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - ROM Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - ROM Game Boy (%1) - - - - All ROMs (%1) - Semua ROM (%1) - - - - %1 Video Logs (*.mvl) - %1 Log Video (*.mvl) - - - + Archives (%1) Arkib (%1) - - - + + + Select ROM Pilih ROM - + Select folder Pilih folder - - + + Select save - + Select patch - + Patches (*.ips *.ups *.bps) - + Select e-Reader dotcode - + e-Reader card (*.raw *.bin *.bmp) - + Select image Pilih gambar - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Fail gambar (*.png *.gif *.jpg *.jpeg);;Semua fail (*) - + GameShark saves (*.sps *.xps) Simpanan GameShark (*.sps *.xps) - + Select video log Pilih log video - + Video logs (*.mvl) Log video (*.mvl) - + Crash Nahas - + The game has crashed with the following error: %1 @@ -5778,684 +6031,699 @@ Download size: %3 %1 - + Couldn't Start Tidak dapat memula - + Could not start game. Permainan tidak dapat bermula. - + Unimplemented BIOS call Panggilan BIOS yg belum dilaksanakan - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Permainan ini menggunakan panggilan BIOS yang belum dilaksanakan. Sila pakai BIOS rasmi untuk pengalaman yang lebih baik. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Gagal mencipta peranti paparan yang sesuai, berbalik ke paparan perisian. Permainan mungkin menjadi lembap, terutamanya dengan tetingkap besar. - + Really make portable? Betulkah mahu buat jadi mudah alih? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? Ini akan menetapkan pelagak untuk muat konfigurasi dari direktori yang sama dengan fail bolehlakunya. Teruskan? - + Restart needed Mula semula diperlukan - + Some changes will not take effect until the emulator is restarted. Beberapa perubahan tidak akan dilaksanakan sehingga pelagak dimula semula. - + - Player %1 of %2 - Pemain %1 dari %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File &File - + Load &ROM... Muat %ROM... - + Load ROM in archive... Muat ROM daripada arkib... - + Add folder to library... Tambah folder ke perpustakaan... - + Save games (%1) Simpanan permainan (%1) - + Select save game Pilih simpanan permainan - + mGBA save state files (%1) mGBA fail keadaan tersimpan (%1) - - + + Select save state Pilih keadaan tersimpan - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) Fail gambar (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Load alternate save game... Muat simpanan permainan alternatif... - + Load temporary save game... Muat simpanan permainan sementara... - + Load &patch... - + Boot BIOS But BIOS - + Replace ROM... Ganti ROM... - + Scan e-Reader dotcodes... - + Convert e-Reader card image to raw... - + ROM &info... &Perihal ROM... - + Recent Terkini - + Make portable Buat jadi mudah alih - + &Load state &Muat keadaan - + Load state file... Muat fail keadaan... - + &Save state &Simpan keadaan - + Save state file... Simpan fail keadaan... - + Quick load - + Quick save - + Load recent Muat terkini - + Save recent Simpan terkini - + Undo load state Buat asal keadaan termuat - + Undo save state Buat asal keadaan tersimpan - - + + State &%1 Keadaan &%1 - + Load camera image... Muat gambar kamera... - + Convert save game... Tukar simpanan permainan... - + GameShark saves (*.gsv *.sps *.xps) - + Reset needed - + Some changes will not take effect until the game is reset. - + Save games Simpanan permainan - + Import GameShark Save... Import Simpanan GameShark... - + Export GameShark Save... Eksport Simpanan GameShark... - + Automatically determine - + Use player %0 save game - + New multiplayer window Tetingkap multipemain baru - + Connect to Dolphin... Sambung ke Dolphin... - + Report bug... Laporkan pepijat... - + About... Perihal... - + E&xit &Keluar - + &Emulation Pe&lagak - + &Reset - + Sh&utdown &Matikan - + Yank game pak Alih keluar Game Pak - + &Pause &Jeda - + &Next frame Bingkai se&terusnya - + Fast forward (held) Mundar laju (pegang) - + &Fast forward Mundar &laju - + Fast forward speed Kelajuan mundar laju - + Unbounded Tidak terbatas - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Putar balik (pegang) - + Re&wind Ma&ndir - + Step backwards Langkah belakang - + Solar sensor Pengesan suria - + Increase solar level Meningkatkan aras suria - + Decrease solar level Mengurangkan aras suria - + Brightest solar level Aras suria paling terang - + Darkest solar level Aras suria paling gelap - + Brightness %1 Kecerahan %1 - + Game Boy Printer... Pencetak Game Boy... - + BattleChip Gate... BattleChip Gate... - + Audio/&Video Audio/&Video - + Frame size Saiz bingkai - + %1× %1× - + Toggle fullscreen Togol skrinpenuh - + Lock aspect ratio Kekalkan nisbah aspek - + Force integer scaling Paksa skala integer - + Interframe blending Persebatian antarabingkai - + Bilinear filtering Penapisan bilinear - + Frame&skip Langkauan &bingkai - + Mute Senyap - + FPS target Sasaran FPS - + Native (59.7275) Asal (59.7275) - + Take &screenshot Ambil &cekupan skrin - + F12 F12 - + Record A/V... Rakam A/V... - + Record GIF/WebP/APNG... Rakam GIF/WebP/APNG... - + Video layers Lapisan video - + Audio channels Saluran audio - + Adjust layer placement... Melaras peletakan lapisan... - + &Tools &Alat - + View &logs... Lihat &log... - + Game &overrides... - + Game Pak sensors... Pengesan Game Pak... - + &Cheats... &Tipu... - + + Create forwarder... + + + + Settings... Tetapan... - + Open debugger console... Buka konsol penyahpepijat... - + Start &GDB server... Mula pelayan &GDB... - + Scripting... - + Game state views - + View &palette... Pelihat &palet... - + View &sprites... - + View &tiles... Pelihat &jubin... - + View &map... Pelihat pe&ta... - + &Frame inspector... Periksa &bingkai... - + View memory... Lihat ingatan... - + Search memory... Cari ingatan... - + View &I/O registers... Lihat daftar &I/O... - + Record debug video log... Rakam log video nyahpepijat... - + Stop debug video log Henti log video nyahpepijat - + Exit fullscreen Keluar skrinpenuh - + GameShark Button (held) Butang GameShark (pegang) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear Kosongkan @@ -6463,55 +6731,70 @@ Download size: %3 QObject - + %1 byte %1 bait - + %1 kiB %1 kiB - + %1 MiB %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + Menu + QShortcut - + Shift Shift - + Control Ctrl - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/ts/mgba-nb_NO.ts b/src/platform/qt/ts/mgba-nb_NO.ts index 05bea134c..128bee3ac 100644 --- a/src/platform/qt/ts/mgba-nb_NO.ts +++ b/src/platform/qt/ts/mgba-nb_NO.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + + + + + Game Boy ROMs (%1) + + + + + All ROMs (%1) + + + + + %1 Video Logs (*.mvl) + + + QGBA::AboutScreen @@ -89,22 +112,22 @@ Nedlastningsstørrelse: %3 QGBA::ApplicationUpdater - + Stable - + Development - + Unknown Ukjent - + (None) @@ -361,48 +384,48 @@ Nedlastningsstørrelse: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 - + Failed to open game file: %1 Klarte ikke å åpne spillfil: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 - + Failed to open snapshot file for writing: %1 @@ -410,17 +433,17 @@ Nedlastningsstørrelse: %3 QGBA::CoreManager - + Failed to open game file: %1 Klarte ikke å åpne spillfil: %1 - + Could not load game. Are you sure it's in the correct format? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -446,7 +469,7 @@ Nedlastningsstørrelse: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -499,6 +522,200 @@ Nedlastningsstørrelse: %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + Bakgrunn + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -537,52 +754,52 @@ Nedlastningsstørrelse: %3 Tilbakestill - + Export frame - + Portable Network Graphics (*.png) - + None Ingen - + Background Bakgrunn - + Window Vindu - + Objwin - + Sprite - + Backdrop - + Frame - + %1 %2 %1 %2 @@ -590,7 +807,7 @@ Nedlastningsstørrelse: %3 QGBA::GBAApp - + Enable Discord Rich Presence @@ -598,22 +815,22 @@ Nedlastningsstørrelse: %3 QGBA::GBAKeyEditor - + Clear Button - + Clear Analog - + Refresh Gjenoppfrisk - + Set all @@ -747,148 +964,168 @@ Nedlastningsstørrelse: %3 QGBA::GameBoy - - + + Autodetect - + Game Boy (DMG) Game Boy (DMG) - + Game Boy Pocket (MGB) Game Boy Pocket (MGB) - + Super Game Boy (SGB) Super Game Boy (SGB) - + Super Game Boy 2 (SGB) Super Game Boy 2 (SGB) - + Game Boy Color (CGB) Game Boy Color (CGB) - + Game Boy Advance (AGB) Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) Super Game Boy Color (SGB + CGB) - + ROM Only Kun ROM - + MBC1 MBC1 - + MBC2 MBC2 - + MBC3 MBC3 - + MBC3 + RTC MBC3 + RTC - + MBC5 MBC5 - + MBC5 + Rumble - + MBC6 MBC6 - + MBC7 (Tilt) - + MMM01 MMM01 - + HuC-1 HuC-1 - + HuC-3 HuC-3 - + Pocket Cam - + TAMA5 TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2766,26 +3003,11 @@ Nedlastningsstørrelse: %3 QGBA::KeyEditor - - + + --- - - - Super (L) - - - - - Super (R) - - - - - Menu - Meny - QGBA::LibraryTree @@ -2907,7 +3129,7 @@ Nedlastningsstørrelse: %3 Skadet - + Slot %1 Plass %1 @@ -3133,39 +3355,39 @@ Nedlastningsstørrelse: %3 - + None Ingen - + Both Begge - + Horizontal - + Vertical - - - + + + N/A I/T - + Export map - + Portable Network Graphics (*.png) @@ -3416,22 +3638,22 @@ Nedlastningsstørrelse: %3 Gjenoppfrisk - + (%0/%1×) - + (⅟%0×) - + (%0×) - + %1 byte%2 @@ -3522,6 +3744,24 @@ Nedlastningsstørrelse: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4020,6 +4260,7 @@ Nedlastningsstørrelse: %3 + (unknown) (ukjent) @@ -4063,6 +4304,11 @@ Nedlastningsstørrelse: %3 CRC32: + + + Save file: + + QGBA::ReportView @@ -4170,7 +4416,7 @@ Nedlastningsstørrelse: %3 - + Cannot convert save games between platforms @@ -4196,92 +4442,97 @@ Nedlastningsstørrelse: %3 - + %1 %2 save game - + little endian - + big endian - + SRAM SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4289,7 +4540,7 @@ Nedlastningsstørrelse: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4435,95 +4686,105 @@ Nedlastningsstørrelse: %3 QGBA::SettingsView - - + + Qt Multimedia - + SDL SDL - + Software (Qt) Programvare (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) - + None Ingen - + None (Still Image) - + Keyboard Tastatur - + Controllers Kontrollere - + Shortcuts Snarveier - - + + Shaders Skyggeleggere - + Select BIOS Velg BIOS - + Select directory Velg mappe - - (%1×%2) - + + Select image + Velg bilde - - Never + + Image file (*.png *.jpg *.jpeg) + (%1×%2) + + + + + Never + + + + Just now - + Less than an hour ago - + %n hour(s) ago @@ -4531,7 +4792,7 @@ Nedlastningsstørrelse: %3 - + %n day(s) ago @@ -4730,7 +4991,7 @@ Nedlastningsstørrelse: %3 - + frames @@ -4818,77 +5079,77 @@ Nedlastningsstørrelse: %3 - + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now - + Default color palette only - + SGB color palette if available - + GBC color palette if available - + SGB (preferred) or GBC color palette if available - + Game Boy Camera - + Driver: - + Source: @@ -4983,58 +5244,68 @@ Nedlastningsstørrelse: %3 - + + Custom border: + + + + Fast forward speed: - - + + Unbounded - + Fast forward (held) speed: - + Autofire interval: - + Enable rewind - + Rewind history: - + + Rewind speed: + + + + Idle loops: - + Run all - + Remove known - + Detect and remove - + Preload entire ROM into memory @@ -5055,42 +5326,42 @@ Nedlastningsstørrelse: %3 - + Models - + GB only: - + SGB compatible: - + GBC only: - + GBC compatible: - + SGB and GBC compatible: - + Game Boy palette - + Preset: @@ -5107,154 +5378,155 @@ Nedlastningsstørrelse: %3 - + Enable Game Boy Player features by default - + Enable VBA bug compatibility in ROM hacks - + Video renderer: - + Software - + OpenGL enhancements - + High-resolution scale: - + (240×160) - + XQ GBA audio (experimental) - + GB BIOS file: - - - - - - - - - + + + + + + + + + + Browse - + Use BIOS file if found - + Skip BIOS intro - + GBA BIOS file: - + GBC BIOS file: - + SGB BIOS file: - + Save games - - - - - + + + + + Same directory as the ROM - + Save states - + Screenshots - + Patches - + Cheats Juks - + Log to file - + Log to console - + Select Log File - + Default BG colors: - + Default sprite colors 1: - + Default sprite colors 2: - + Super Game Boy borders @@ -5267,27 +5539,28 @@ Nedlastningsstørrelse: %3 Ingen aktive skyggeleggere - + + Load shader Last inn skyggelegger - + No shader loaded - + by %1 av %1 - + Preprocessing - + Pass %1 @@ -5330,17 +5603,17 @@ Nedlastningsstørrelse: %3 QGBA::ShortcutModel - + Action Handling - + Keyboard Tastatur - + Gamepad @@ -5460,17 +5733,17 @@ Nedlastningsstørrelse: %3 QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file Velg utdatafil @@ -5681,784 +5954,779 @@ Nedlastningsstørrelse: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - - - - - Game Boy ROMs (%1) - - - - - All ROMs (%1) - - - - - %1 Video Logs (*.mvl) - - - - + Archives (%1) Arkiv (%1) - - - + + + Select ROM Velg ROM - + Select folder Velg mappe - - + + Select save - + Select patch Velg feilfiks - + Patches (*.ips *.ups *.bps) Feilfikser (*.ips *.ups *.bps) - + Select e-Reader dotcode - + e-Reader card (*.raw *.bin *.bmp) - + Select image Velg bilde - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Bildefil (*.png *.gif *.jpg *.jpeg);;All filer (*) - + GameShark saves (*.sps *.xps) - + Select video log - + Video logs (*.mvl) - + Crash Krasj - + The game has crashed with the following error: %1 - + Couldn't Start - + Could not start game. - + Unimplemented BIOS call - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. - + Really make portable? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - + Restart needed - + Some changes will not take effect until the emulator is restarted. - + - Player %1 of %2 - + %1 - %2 - + %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File - + Load &ROM... - + Load ROM in archive... - + Add folder to library... - + Save games (%1) - + Select save game - + mGBA save state files (%1) - - + + Select save state - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Load alternate save game... - + Load temporary save game... - + Load &patch... - + Boot BIOS - + Replace ROM... - + Scan e-Reader dotcodes... - + Convert e-Reader card image to raw... - + ROM &info... - + Recent - + Make portable - + &Load state - + Load state file... - + &Save state - + Save state file... - + Quick load - + Quick save - + Load recent - + Save recent - + Undo load state - + Undo save state - - + + State &%1 - + Load camera image... - + Convert save game... - + GameShark saves (*.gsv *.sps *.xps) - + Reset needed - + Some changes will not take effect until the game is reset. - + Save games - + Import GameShark Save... - + Export GameShark Save... - + Automatically determine - + Use player %0 save game - + New multiplayer window - + Connect to Dolphin... - + Report bug... - + About... - + E&xit - + &Emulation - + &Reset - + Sh&utdown - + Yank game pak - + &Pause - + &Next frame - + Fast forward (held) - + &Fast forward - + Fast forward speed - + Unbounded - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) - + Re&wind - + Step backwards - + Solar sensor - + Increase solar level - + Decrease solar level - + Brightest solar level - + Darkest solar level - + Brightness %1 - + Game Boy Printer... - + BattleChip Gate... - + Audio/&Video - + Frame size - + %1× %1× - + Toggle fullscreen - + Lock aspect ratio - + Force integer scaling - + Interframe blending - + Bilinear filtering - + Frame&skip - + Mute - + FPS target - + Native (59.7275) - + Take &screenshot - + F12 - + Record A/V... - + Record GIF/WebP/APNG... - + Video layers - + Audio channels - + Adjust layer placement... - + &Tools - + View &logs... - + Game &overrides... - + Game Pak sensors... - + &Cheats... - + + Create forwarder... + + + + Settings... - + Open debugger console... - + Start &GDB server... - + Scripting... - + Game state views - + View &palette... - + View &sprites... - + View &tiles... - + View &map... - + &Frame inspector... - + View memory... - + Search memory... - + View &I/O registers... - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear Tøm @@ -6466,55 +6734,70 @@ Nedlastningsstørrelse: %3 QObject - + %1 byte - + %1 kiB - + %1 MiB - + GBA - + GB - + ? + + + Super (L) + + + + + Super (R) + + + + + Menu + Meny + QShortcut - + Shift - + Control - + Alt - + Meta diff --git a/src/platform/qt/ts/mgba-pl.ts b/src/platform/qt/ts/mgba-pl.ts index b1a95e463..180b32630 100644 --- a/src/platform/qt/ts/mgba-pl.ts +++ b/src/platform/qt/ts/mgba-pl.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ROMy Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROMy Game Boy (%1) + + + + All ROMs (%1) + Wszystkie ROMy (%1) + + + + %1 Video Logs (*.mvl) + Dzienniki wideo %1 (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Rozmiar pobierania: %3 QGBA::ApplicationUpdater - + Stable Stabilna - + Development Rozwojowa - + Unknown Nieznana - + (None) (Żadna) @@ -364,48 +387,48 @@ Rozmiar pobierania: %3 QGBA::CoreController - + Reset r%1-%2 %3 Reset r%1-%2 %3 - - + + Rewinding not currently enabled Przewijanie nie jest obecnie włączone - + Reset the game? Zresetować grę? - + Most games will require a reset to load the new save. Do you want to reset now? Większość gier wymaga zresetowania, aby wczytać nowy zapis. Czy chcesz teraz zresetować? - + Failed to open save file: %1 Nie udało się otworzyć pliku zapisu: %1 - + Failed to open game file: %1 Nie udało się otworzyć pliku gry: %1 - + Can't yank pack in unexpected platform! Nie można wyciągnąć pack na nieoczekiwanej platformie! - + Failed to open snapshot file for reading: %1 Nie udało się otworzyć pliku snapshot do odczytu: %1 - + Failed to open snapshot file for writing: %1 Nie udało się otworzyć pliku snapshot do zapisu: %1 @@ -413,17 +436,17 @@ Rozmiar pobierania: %3 QGBA::CoreManager - + Failed to open game file: %1 Nie udało się otworzyć pliku gry: %1 - + Could not load game. Are you sure it's in the correct format? Nie udało się wczytać gry. Czy na pewno jest we właściwym formacie? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). Nie udało się otworzyć pliku zapisu; zapisy w grze nie mogą być aktualizowane. Upewnij się, że katalog zapisu jest zapisywalny bez dodatkowych uprawnień (np. UAC w systemie Windows). @@ -449,7 +472,7 @@ Rozmiar pobierania: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing Nie można otworzyć historii CLI do zapisu @@ -502,6 +525,200 @@ Rozmiar pobierania: %3 Nie udało się połączyć z Dolphinem. + + QGBA::ForwarderGenerator + + + 3DS + 3DS + + + + Vita + Vita + + + + QGBA::ForwarderGenerator3DS + + + Icon + Ikona + + + + Banner + Baner + + + + QGBA::ForwarderGeneratorVita + + + Bubble + Bańka + + + + Background + Tło + + + + Startup + Uruchomienie + + + + QGBA::ForwarderView + + + Create forwarder + Utwórz forwardera + + + + Files + Pliki + + + + ROM file: + Plik ROM: + + + + + + Browse + Przeglądaj + + + + Output filename: + Nazwa pliku wyjściowego: + + + + Forwarder base: + Baza forwardera: + + + + Latest stable version + Najnowsza stabilna wersja + + + + Latest development build + Najnowsza kompilacja deweloperska + + + + Specific file + Konkretny plik + + + + Base file: + Plik bazowy: + + + + System + System + + + + 3DS + 3DS + + + + Vita + Vita + + + + Presentation + Prezentacja + + + + Title: + Tytuł: + + + + Images: + Obrazy: + + + + Use default image + Użyj obrazu domyślnego + + + + Preferred size: + Preferowany rozmiar: + + + + Select image file + Wybierz plik obrazu + + + + Select ROM file + Wybierz plik ROM + + + + Select output filename + Wybierz nazwę pliku wyjściowego + + + + Select base file + Wybierz plik bazowy + + + + Build finished + Kompilacja zakończona + + + + Forwarder finished building + Forwarder zakończył kompilację + + + + Build failed + Kompilacja nie powiodła się + + + + Failed to build forwarder + Nie udało się skompilować forwardera + + + + %1 installable package (*.%2) + Pakiet instalacyjny %1 (*.%2) + + + + Select an image + Wybierz obraz + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Rozmiar pobierania: %3 Resetuj - + Export frame Eksportuj klatkę - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Nic - + Background Tło - + Window Okno - + Objwin Obiwin - + Sprite Sprite - + Backdrop Zasłona - + Frame Klatka - + %1 %2 %1 %2 @@ -593,7 +810,7 @@ Rozmiar pobierania: %3 QGBA::GBAApp - + Enable Discord Rich Presence Włącz Discord Rich Presence @@ -601,22 +818,22 @@ Rozmiar pobierania: %3 QGBA::GBAKeyEditor - + Clear Button Wyczyść Przycisk - + Clear Analog Wyczyść Analog - + Refresh Odśwież - + Set all Ustaw wszystko @@ -750,148 +967,168 @@ Rozmiar pobierania: %3 QGBA::GameBoy - - + + Autodetect Automatyczne wykrywanie - + Game Boy (DMG) Game Boy (DMG) - + Game Boy Pocket (MGB) Game Boy Pocket (MGB) - + Super Game Boy (SGB) Super Game Boy (SGB) - + Super Game Boy 2 (SGB) Super Game Boy 2 (SGB) - + Game Boy Color (CGB) Game Boy Color (CGB) - + Game Boy Advance (AGB) Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) Super Game Boy Color (SGB + CGB) - + ROM Only Tylko ROM - + MBC1 MBC1 - + MBC2 MBC2 - + MBC3 MBC3 - + MBC3 + RTC MBC3 + RTC - + MBC5 MBC5 - + MBC5 + Rumble MBC5 + Rumble - + MBC6 MBC6 - + MBC7 (Tilt) MBC7 (Przechylenie) - + MMM01 MMM01 - + HuC-1 HuC-1 - + HuC-3 HuC-3 - + Pocket Cam Pocket Cam - + TAMA5 TAMA5 - + Wisdom Tree Wisdom Tree - + + NT (old 1) + NT (stary 1) + + + + NT (old 2) + NT (stary 2) + + + NT (new) NT (nowy) - + Pokémon Jade/Diamond Pokémon Jade/Diamond - + BBD BBD - + Hitek Hitek - + + GGB-81 + GGB-81 + + + + Li Cheng + Li Cheng + + + Sachen (MMC1) Sachen (MMC1) - + Sachen (MMC2) Sachen (MMC2) @@ -2769,26 +3006,11 @@ Rozmiar pobierania: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (L) - - - - Super (R) - Super (R) - - - - Menu - Menu - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Rozmiar pobierania: %3 Uszkodzony - + Slot %1 Slot %1 @@ -3136,39 +3358,39 @@ Rozmiar pobierania: %3 Odbicie - + None Nic - + Both Obydwa - + Horizontal Poziomy - + Vertical Pionowy - - - + + + N/A N/D - + Export map Eksportuj mapę - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3419,22 +3641,22 @@ Rozmiar pobierania: %3 Odśwież - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 bajt%2 @@ -3525,6 +3747,24 @@ Rozmiar pobierania: %3 Klatka %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4023,6 +4263,7 @@ Rozmiar pobierania: %3 + (unknown) (nieznany) @@ -4066,6 +4307,11 @@ Rozmiar pobierania: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4173,7 +4419,7 @@ Rozmiar pobierania: %3 Nie znaleziono prawidłowych konwersji - + Cannot convert save games between platforms Nie można konwertować zapisanych gier między platformami @@ -4199,92 +4445,97 @@ Rozmiar pobierania: %3 Plik wyjściowy - + %1 %2 save game %1 %2 zapis gry - + little endian little endian - + big endian big endian - + SRAM SRAM - + %1 flash %1 flash - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 MBC2 skompresowane - + unpacked MBC2 MBC2 nieskompresowany - + MBC6 flash MBC6 Flash - + MBC6 combined SRAM + flash MBC6 łączny SRAM + flash - + MBC6 SRAM MBC6 SRAM - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game %1 stan gry z osadzonym %2 zapisem gry - + %1 SharkPort %2 save game %1 SharkPort %2 zapis gry - + %1 GameShark Advance SP %2 save game %1 GameShark Advance SP %2 zapis gry @@ -4292,7 +4543,7 @@ Rozmiar pobierania: %3 QGBA::ScriptingTextBuffer - + Untitled buffer Bufor bez tytułu @@ -4438,95 +4689,105 @@ Rozmiar pobierania: %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimedia - + SDL SDL - + Software (Qt) Software (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (wymuś wersję 1.x) - + None Nic - + None (Still Image) Brak (Obraz Nieruchomy) - + Keyboard Klawiatura - + Controllers Kontrolery - + Shortcuts Skróty - - + + Shaders Shadery - + Select BIOS Wybierz BIOS - + Select directory Wybierz katalog - + + Select image + Wybierz obraz + + + + Image file (*.png *.jpg *.jpeg) + Plik graficzny (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never Nigdy - + Just now Właśnie teraz - + Less than an hour ago Mniej niż godzinę temu - + %n hour(s) ago %n godzinę temu @@ -4535,7 +4796,7 @@ Rozmiar pobierania: %3 - + %n day(s) ago %n dzień temu @@ -4735,7 +4996,7 @@ Rozmiar pobierania: %3 - + frames klatki @@ -4823,77 +5084,77 @@ Rozmiar pobierania: %3 Po zminimalizowaniu: - + Current channel: Aktualny kanał: - + Current version: Obecna wersja: - + Update channel: Kanał aktualizacji: - + Available version: Dostępna wersja: - + (Unknown) (Nieznany) - + Last checked: Ostatnio sprawdzane: - + Automatically check on start Automatycznie sprawdź przy starcie - + Check now Sprawdź teraz - + Default color palette only Tylko domyślna paleta kolorów - + SGB color palette if available Paleta kolorów SGB, jeśli jest dostępna - + GBC color palette if available Paleta kolorów GBC, jeśli jest dostępna - + SGB (preferred) or GBC color palette if available Paleta kolorów SGB (preferowana) lub GBC, jeśli jest dostępna - + Game Boy Camera Game Boy Camera - + Driver: Sterownik: - + Source: Źródło: @@ -4988,58 +5249,68 @@ Rozmiar pobierania: %3 Pokaż informacje o emulacji po zresetowaniu - + + Custom border: + + + + Fast forward speed: Szybkość przewijania do przodu: - - + + Unbounded Bez ograniczeń - + Fast forward (held) speed: Szybkość przewijania do przodu (przytrzymana): - + Autofire interval: Interwał turbo: - + Enable rewind Włącz przewijanie - + Rewind history: Historia przewijania: - + + Rewind speed: + + + + Idle loops: Bezczynne pętle: - + Run all Uruchom wszystko - + Remove known Usuń znane - + Detect and remove Wykryj i usuń - + Preload entire ROM into memory Wstępnie załaduj całą pamięć ROM do pamięci @@ -5060,42 +5331,42 @@ Rozmiar pobierania: %3 Dodatkowe dane ładowania stanu gry: - + Models Modele - + GB only: Tylko GB: - + SGB compatible: Kompatybilny z SGB: - + GBC only: Tylko GBC: - + GBC compatible: Kompatybilny z GBC: - + SGB and GBC compatible: Kompatybilny z SGB i GBC: - + Game Boy palette Paleta Game Boy - + Preset: Ustawienie wstępne: @@ -5112,154 +5383,155 @@ Rozmiar pobierania: %3 Kody - + Enable Game Boy Player features by default Włącz domyślnie funkcje Game Boy Playera - + Enable VBA bug compatibility in ROM hacks Włącz zgodność błędów VBA w hackach ROM - + Video renderer: Renderowanie wideo: - + Software Software - + OpenGL enhancements Ulepszenia OpenGL - + High-resolution scale: Skala o wysokiej rozdzielczości: - + (240×160) (240×160) - + XQ GBA audio (experimental) Dźwięk wysokiej jakości GBA (eksperymentalny) - + GB BIOS file: Plik BIOS GB: - - - - - - - - - + + + + + + + + + + Browse Przeglądaj - + Use BIOS file if found Użyj pliku BIOS, jeśli zostanie znaleziony - + Skip BIOS intro Pomiń wprowadzenie BIOS - + GBA BIOS file: Plik BIOS GBA: - + GBC BIOS file: Plik BIOS GBC: - + SGB BIOS file: Plik BIOS SGB: - + Save games Zapisane gry - - - - - + + + + + Same directory as the ROM Ten sam katalog co ROM - + Save states Stany gry - + Screenshots Zrzuty ekranu - + Patches Łatki - + Cheats Kody (cheaty) - + Log to file Loguj do pliku - + Log to console Loguj do konsoli - + Select Log File Wybierz plik dziennika - + Default BG colors: Domyślne kolory tła: - + Default sprite colors 1: Domyślne kolory sprite'ów 1: - + Default sprite colors 2: Domyślne kolory sprite'ów 2: - + Super Game Boy borders Ramki Super Game Boy @@ -5272,27 +5544,28 @@ Rozmiar pobierania: %3 Brak aktywnych shaderów - + + Load shader Załaduj shader - + No shader loaded Nie załadowano shadera - + by %1 autorstwa %1 - + Preprocessing Przetwarzanie wstępne - + Pass %1 Przejście %1 @@ -5335,17 +5608,17 @@ Rozmiar pobierania: %3 QGBA::ShortcutModel - + Action Akcja - + Keyboard Klawiatura - + Gamepad Kontroler @@ -5465,17 +5738,17 @@ Rozmiar pobierania: %3 QGBA::VideoView - + Failed to open output video file: %1 Nie udało się otworzyć wyjściowego pliku wideo: %1 - + Native (%0x%1) Natywny (%0x%1) - + Select output file Wybierz plik wyjściowy @@ -5610,7 +5883,7 @@ Rozmiar pobierania: %3 WavPack - + WavPack @@ -5686,100 +5959,80 @@ Rozmiar pobierania: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - ROMy Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - ROMy Game Boy (%1) - - - - All ROMs (%1) - Wszystkie ROMy (%1) - - - - %1 Video Logs (*.mvl) - Dzienniki wideo %1 (*.mvl) - - - + Archives (%1) Archiwa (%1) - - - + + + Select ROM Wybierz ROM - + Select folder Wybierz katalog - - + + Select save Wybierz zapis - + Select patch Wybierz łatkę - + Patches (*.ips *.ups *.bps) Łatki (*.ips *.ups *.bps) - + Select e-Reader dotcode Wybierz kod kropki e-Reader - + e-Reader card (*.raw *.bin *.bmp) Karta e-Reader (*.raw *.bin *.bmp) - + Select image Wybierz obraz - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Plik obrazu (*.png *.gif *.jpg *.jpeg);;Wszystkie pliki (*) - + GameShark saves (*.sps *.xps) Zapisy GameShark (*.sps *.xps) - + Select video log Wybierz dziennik wideo - + Video logs (*.mvl) Dzienniki wideo (*.mvl) - + Crash Crash - + The game has crashed with the following error: %1 @@ -5788,684 +6041,699 @@ Rozmiar pobierania: %3 %1 - + Couldn't Start Nie udało się uruchomić - + Could not start game. Nie udało się rozpocząć gry. - + Unimplemented BIOS call Niewdrożone wywołanie BIOS - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Ta gra używa wywołania BIOS, które nie jest zaimplementowane. Aby uzyskać najlepsze wrażenia, użyj oficjalnego BIOS. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Nie udało się utworzyć odpowiedniego urządzenia wyświetlającego, powracam do wyświetlania programowego. Gry mogą działać wolno, zwłaszcza w przypadku większych okien. - + Really make portable? Naprawdę stworzyć wersję portable? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? To sprawi, że emulator załaduje swoją konfigurację z tego samego katalogu, co plik wykonywalny. Czy chcesz kontynuować? - + Restart needed Wymagane ponowne uruchomienie - + Some changes will not take effect until the emulator is restarted. Niektóre zmiany nie zaczną obowiązywać, dopóki emulator nie zostanie ponownie uruchomiony. - + - Player %1 of %2 - Gracz %1 z %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 FPS) - %4 - + &File &Plik - + Load &ROM... Załaduj &ROM... - + Load ROM in archive... Załaduj ROM w archiwum... - + Add folder to library... Dodaj folder do biblioteki... - + Save games (%1) Zapisane gry (%1) - + Select save game Wybierz zapis gry - + mGBA save state files (%1) Pliki stanu gry mGBA (%1) - - + + Select save state Wybierz stan - + Select e-Reader card images Wybierz obrazy kart e-Reader - + Image file (*.png *.jpg *.jpeg) Plik graficzny (*.png *.jpg *.jpeg) - + Conversion finished Konwersja zakończona - + %1 of %2 e-Reader cards converted successfully. %1 z %2 kart czytnika e-Reader zostało pomyślnie przekonwertowanych. - + Load alternate save game... Załaduj alternatywny zapis gry... - + Load temporary save game... Załaduj tymczasowy zapis gry... - + Load &patch... Wczytaj &poprawkę... - + Boot BIOS BIOS startowy - + Replace ROM... Wymień ROM... - + Scan e-Reader dotcodes... Skanuj kody kropkowe czytnika e-Reader... - + Convert e-Reader card image to raw... Konwertuj obraz karty czytnika e-Reader na surowy... - + ROM &info... &Informacje o pamięci ROM... - + Recent Ostatnie - + Make portable Stwórz wersję portable - + &Load state &Załaduj stan - + Load state file... Załaduj plik stanu… - + &Save state &Zapisz stan - + Save state file... Zapisz plik stanu... - + Quick load Szybkie załadowanie - + Quick save Szybki zapis - + Load recent Załaduj ostatnie - + Save recent Zapisz ostatnie - + Undo load state Cofnij załadowanie stanu - + Undo save state Cofnij zapisanie stanu - - + + State &%1 Stan &%1 - + Load camera image... Załaduj obraz do kamery... - + Convert save game... Konwertuj zapisaną grę... - + GameShark saves (*.gsv *.sps *.xps) Zapisy GameShark (*.gsv *.sps *.xps) - + Reset needed Wymagane zresetowanie - + Some changes will not take effect until the game is reset. Niektóre zmiany nie zaczną obowiązywać, dopóki gra nie zostanie zresetowana. - + Save games Zapisy gry - + Import GameShark Save... Importuj Zapis GameShark... - + Export GameShark Save... Eksportuj Zapis GameShark... - + Automatically determine Wykryj automatycznie - + Use player %0 save game Użyj zapis gry gracza %0 - + New multiplayer window Nowe okno dla wielu graczy - + Connect to Dolphin... Połącz z Dolphinem... - + Report bug... Zgłoś błąd... - + About... O Aplikacji... - + E&xit Z&akończ - + &Emulation &Emulacja - + &Reset &Resetuj - + Sh&utdown Za&mknij - + Yank game pak Wyciągnij Game Pak - + &Pause &Pauza - + &Next frame &Następna klatka - + Fast forward (held) Przewijanie (przytrzymaj) - + &Fast forward &Przewijanie do przodu - + Fast forward speed Prędkość przewijania do przodu - + Unbounded Bez ograniczeń - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Przewijanie (przytrzymaj) - + Re&wind Pr&zewijanie - + Step backwards Krok w tył - + Solar sensor Czujnik słoneczny - + Increase solar level Zwiększ poziom energii słonecznej - + Decrease solar level Zmniejsz poziom energii słonecznej - + Brightest solar level Najjaśniejszy poziom energii słonecznej - + Darkest solar level Najciemniejszy poziom energii słonecznej - + Brightness %1 Jasność %1 - + Game Boy Printer... Game Boy Printer... - + BattleChip Gate... BattleChip Gate... - + Audio/&Video Dźwięk/&Wideo - + Frame size Rozmiar klatki - + %1× %1× - + Toggle fullscreen Przełącz tryb pełnoekranowy - + Lock aspect ratio Zablokuj proporcje - + Force integer scaling Wymuś skalowanie całkowite - + Interframe blending Blendowanie międzyklatkowe - + Bilinear filtering Filtrowanie dwuliniowe - + Frame&skip Klatko&wanie - + Mute Wycisz - + FPS target Cel KL./S - + Native (59.7275) Natywny (59.7275) - + Take &screenshot Wykonaj &zrzut ekranu - + F12 F12 - + Record A/V... Nagraj A/W... - + Record GIF/WebP/APNG... Nagraj GIF/WebP/APNG... - + Video layers Warstwy wideo - + Audio channels Kanały audio - + Adjust layer placement... Dostosuj położenie warstw... - + &Tools &Narzędzia - + View &logs... Wyświetl &logi... - + Game &overrides... Nadpisania &ustawień gry... - + Game Pak sensors... Czujniki Game Pak... - + &Cheats... &Kody... - + + Create forwarder... + Utwórz forwarder... + + + Settings... Ustawienia... - + Open debugger console... Otwórz konsolę debugera... - + Start &GDB server... Uruchom serwer &GDB... - + Scripting... Skrypty... - + Game state views Widoki stanu gry - + View &palette... Wyświetl &paletę... - + View &sprites... Wyświetl &sprite'y... - + View &tiles... Wyświetl &kafelki... - + View &map... Wyświetl &mapę... - + &Frame inspector... Inspektor &klatek... - + View memory... Wyświetl pamięć... - + Search memory... Przeszukaj pamięć... - + View &I/O registers... Wyświetl rejestry &we/wy... - + Record debug video log... Nagraj dziennik wideo debugowania... - + Stop debug video log Zatrzymaj dziennik wideo debugowania - + Exit fullscreen Wyłączyć tryb pełnoekranowy - + GameShark Button (held) Przycisk GameShark (przytrzymany) - + Autofire Turbo - + Autofire A Turbo A - + Autofire B Turbo B - + Autofire L Turbo L - + Autofire R Turbo R - + Autofire Start Turbo Start - + Autofire Select Turbo Select - + Autofire Up Turbo Góra - + Autofire Right Turbo Prawo - + Autofire Down Turbo Dół - + Autofire Left Turbo Lewo - + Clear Wyczyść @@ -6473,55 +6741,70 @@ Rozmiar pobierania: %3 QObject - + %1 byte %1 bajt - + %1 kiB %1 kiB - + %1 MiB %1 MiB - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super (L) + + + + Super (R) + Super (R) + + + + Menu + Menu + QShortcut - + Shift Shift - + Control Control - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/ts/mgba-pt.ts b/src/platform/qt/ts/mgba-pt.ts new file mode 100644 index 000000000..72af03abe --- /dev/null +++ b/src/platform/qt/ts/mgba-pt.ts @@ -0,0 +1,6810 @@ + + + + + QGBA + + + Game Boy Advance ROMs (%1) + ROMs do Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROMs do Game Boy (%1) + + + + All ROMs (%1) + Todas as ROMs (%1) + + + + %1 Video Logs (*.mvl) + %1 Registos do Vídeo (*.mvl) + + + + QGBA::AboutScreen + + + About + Sobre + + + + <a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Forums / Support</a> • <a href="https://patreon.com/mgba">Donate</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Source</a> + <a href="http://mgba.io/">Site da Web</a> • <a href="https://forums.mgba.io/">Fóruns / Suporte</a> • <a href="https://patreon.com/mgba">Doar</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Fonte</a> + + + + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + Branch: <tt>{gitBranch}</tt><br/>Revisão: <tt>{gitCommit}</tt> + + + + {projectName} would like to thank the following patrons from Patreon: + O {projectName} gostaria de agradecer aos seguintes patronos do Patreon: + + + + © 2013 – {year} Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + © 2013 – {year} Jeffrey Pfau, licenciado sob a Licença Pública do Mozilla, versão 2.0 +O Game Boy Advance é uma marca registada da Nintendo Co., Ltd. + + + + {projectName} is an open-source Game Boy Advance emulator + O {projectName} é um emulador de Game Boy Advance de código fonte aberto + + + + QGBA::ApplicationUpdatePrompt + + + An update is available + Uma atualização está disponível + + + + An update to %1 is available. + + Uma atualização para o %1 está disponível. + + + + + +Do you want to download and install it now? You will need to restart the emulator when the download is complete. + +Quer descarregar e instalá-lo agora? Precisará reiniciar o emulador quando a descarga estiver completa. + + + + +Auto-update is not available on this platform. If you wish to update you will need to do it manually. + +Uma auto-atualização não está disponível nesta plataforma. Se deseja atualizar precisará fazê-lo manualmente. + + + + Current version: %1 +New version: %2 +Download size: %3 + Versão atual: %1 +Nova versão: %2 +Tamanho da descarga: %3 + + + + Downloading update... + A descarregar a atualização... + + + + Downloading failed. Please update manually. + A descarga falhou. Por favor, atualize manualmente. + + + + Downloading done. Press OK to restart %1 and install the update. + Descarga concluída. Pressione Ok para reiniciar o %1 e instalar a atualização. + + + + QGBA::ApplicationUpdater + + + Stable + Estável + + + + Development + Desenvolvimento + + + + Unknown + Desconhecido + + + + (None) + (Nenhum) + + + + QGBA::ArchiveInspector + + + Open in archive... + Abrir no arquivo... + + + + Loading... + A carregar... + + + + QGBA::AssetTile + + + Tile # + Ladrilho # + + + + Palette # + Paleta # + + + + Address + Endereço + + + + Red + Vermelho + + + + Green + Verde + + + + Blue + Azul + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + QGBA::AudioDevice + + + Can't set format of context-less audio device + Não pôde definir o formato do aparelho de áudio sem contexto + + + + Audio device is missing its core + O núcleo do aparelho de áudio está ausente + + + + Writing data to read-only audio device + Gravando dados no aparelho somente-leitura do áudio + + + + QGBA::AudioProcessorQt + + + Can't start an audio processor without input + Não pôde iniciar um processador de áudio sem entrada + + + + QGBA::AudioProcessorSDL + + + Can't start an audio processor without input + Não pôde iniciar um processador de áudio sem entrada + + + + QGBA::BattleChipView + + + BattleChip Gate + Portal do BattleChip + + + + Chip name + Nome do chip + + + + Insert + Inserir + + + + Save + Gravar + + + + Load + Carregar + + + + Add + Adicionar + + + + Remove + Remover + + + + Gate type + Tipo de Portal + + + + Inserted + Inserido + + + + Chip ID + ID do Chip + + + + Update Chip data + Atualizar os dados do Chip + + + + Show advanced + Mostrar as opções avançadas + + + + BattleChip data missing + Portal do BattleChip + + + + BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? + Os dados do BattleChip estão ausentes. O BattleChip Gates ainda funcionará, mas alguns gráficos estarão ausentes. Gostaria de descarregar os dados agora? + + + + + Select deck file + Selecionar o ficheiro do deck + + + + Incompatible deck + Deck incompatível + + + + The selected deck is not compatible with this Chip Gate + O deck selecionado não é compatível com este Portal do Chip + + + + QGBA::CheatsModel + + + (untitled) + (sem título) + + + + Failed to open cheats file: %1 + Falha ao abrir o ficheiro das trapaças: %1 + + + + QGBA::CheatsView + + + Cheats + Trapaças + + + + Add New Code + Adicionar Novo Código + + + + Remove + Remover + + + + Add Lines + Adicionar Linhas + + + + Code type + Tipo de código + + + + Save + Gravar + + + + Load + Carregar + + + + Enter codes here... + Insira os códigos aqui... + + + + + Autodetect (recommended) + Auto-detetar (recomendado) + + + + + Select cheats file + Selecionar o ficheiro das trapaças + + + + Some cheats could not be added. Please ensure they're formatted correctly and/or try other cheat types. + Algumas trapaças não puderam ser adicionadas. Por favor tenha certeza que eles estão formatadas corretamente e/ou tente outros tipos de trapaça. + + + + QGBA::CoreController + + + Reset r%1-%2 %3 + Resetar r%1-%2 %3 + + + + + Rewinding not currently enabled + O rebobinamento não está ativado atualmente + + + + Reset the game? + Resetar o jogo? + + + + Most games will require a reset to load the new save. Do you want to reset now? + A maioria dos jogos requerirão um reset para carregar o novo save. Quer resetar agora? + + + + Failed to open save file: %1 + Falha ao abrir o ficheiro dde gravação: %1 + + + + Failed to open game file: %1 + Falha ao abrir o ficheiro do jogo: %1 + + + + Can't yank pack in unexpected platform! + Não pode arrancar o pacote numa plataforma inesperada! + + + + Failed to open snapshot file for reading: %1 + Falha ao abrir o ficheiro do snapshot para leitura: %1 + + + + Failed to open snapshot file for writing: %1 + Falha ao abrir o ficheiro do snapshot para gravação: %1 + + + + QGBA::CoreManager + + + Failed to open game file: %1 + Falha ao abrir o ficheiro do jogo: %1 + + + + Could not load game. Are you sure it's in the correct format? + Não pôde carregar o jogo. Tem certeza que está no formato correto? + + + + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). + Falha ao abrir o ficheiro de save; os saves dentro do jogo não podem ser atualizados. Por favor tenha certeza que o diretório de save seja gravável sem privilégios adicionais (ex: UAC no Windows). + + + + QGBA::DebuggerConsole + + + Debugger + Debugger + + + + Enter command (try `help` for more info) + Insira o comando (tente `help` para mais informações) + + + + Break + Parar + + + + QGBA::DebuggerConsoleController + + + Could not open CLI history for writing + Não pôde abrir o histórico do CLI para gravar + + + + QGBA::DolphinConnector + + + Connect to Dolphin + Conectar ao Dolphin + + + + Local computer + Computador local + + + + IP address + Endereço do IP + + + + Connect + Conectar + + + + Disconnect + Desconectar + + + + Close + Fechar + + + + Reset on connect + Resetar ao conectar + + + + Couldn't Connect + Não Pôde Conectar + + + + Could not connect to Dolphin. + Não pôde conectar com o Dolphin. + + + + QGBA::ForwarderGenerator + + + 3DS + 3DS + + + + Vita + Vita + + + + QGBA::ForwarderGenerator3DS + + + Icon + Ícone + + + + Banner + Banner + + + + QGBA::ForwarderGeneratorVita + + + Bubble + Bolha + + + + Background + 2º plano + + + + Startup + Inicialização + + + + QGBA::ForwarderView + + + Create forwarder + Criar encaminhador + + + + Files + Ficheiros + + + + ROM file: + Ficheiro da ROM: + + + + + + Browse + Explorar + + + + Output filename: + Nome do ficheiro de saída: + + + + Forwarder base: + Base do encaminhador: + + + + Latest stable version + Última versão estável + + + + Latest development build + Último build de desenvolvimento + + + + Specific file + Ficheiro específico + + + + Base file: + Ficheiro base: + + + + System + Sistema + + + + 3DS + 3DS + + + + Vita + Vita + + + + Presentation + Apresentação + + + + Title: + Título: + + + + Images: + Imagens: + + + + Use default image + Usar imagem padrão + + + + Preferred size: + Tamanho preferido: + + + + Select image file + Selecionar ficheiro de imagem + + + + Select ROM file + Selecione o ficheiro da ROM + + + + Select output filename + Selecionar o nome do ficheiro de saída + + + + Select base file + Selecionar o ficheiro base + + + + Build finished + Compilação concluída + + + + Forwarder finished building + O encaminhador encerrou a compilação + + + + Build failed + Falhou em criar o build + + + + Failed to build forwarder + Falhou em criar o encaminhador + + + + %1 installable package (*.%2) + %1 pacote instalável (*.%2) + + + + Select an image + Selecione uma imagem + + + + Image files (*.png *.jpg *.bmp) + + + + + QGBA::FrameView + + + Inspect frame + Inspecionar frame + + + + Magnification + Ampliação + + + + Freeze frame + Congelar frame + + + + Backdrop color + Cor do 2º plano + + + + Disable scanline effects + Desativar efeitos da scanline + + + + Export + Exportar + + + + Reset + Resetar + + + + Export frame + Exportar frame + + + + Portable Network Graphics (*.png) + Gráficos Portáteis da Rede (*.png) + + + + None + Nenhum + + + + Background + 2º plano + + + + Window + Janela + + + + Objwin + Objwin + + + + Sprite + Imagem Móvel + + + + Backdrop + 2º Plano + + + + Frame + Frame + + + + %1 %2 + %1 %2 + + + + QGBA::GBAApp + + + Enable Discord Rich Presence + Ativar o Discord Rich Presence + + + + QGBA::GBAKeyEditor + + + Clear Button + Limpar Botão + + + + Clear Analog + Limpar Analógico + + + + Refresh + Atualizar + + + + Set all + Definir todos + + + + QGBA::GDBWindow + + + Server settings + Configurações do servidor + + + + Local port + Porta local + + + + Bind address + Vincular endereço + + + + Write watchpoints behavior + Gravar o comportamento dos pontos de observação + + + + Standard GDB + GDB padrão + + + + Internal change detection + Detecção das mudanças internas + + + + Break on all writes + Interromper todas as gravações + + + + Break + Pausar + + + + Stop + Parar + + + + Start + Iniciar + + + + Crash + Crash + + + + Could not start GDB server + Não pôde iniciar o servidor do GDB + + + + QGBA::GIFView + + + Record GIF/WebP/APNG + Gravar GIF/WebP/APNG + + + + Loop + Repetição + + + + Start + Iniciar + + + + Stop + Parar + + + + Select File + Selecionar ficheiro + + + + APNG + APNG + + + + GIF + GIF + + + + WebP + WebP + + + + Frameskip + Frameskip + + + + Failed to open output file: %1 + Falhou em abrir o ficheiro de saída: %1 + + + + Select output file + Selecionar o ficheiro de saída + + + + Graphics Interchange Format (*.gif);;WebP ( *.webp);;Animated Portable Network Graphics (*.png *.apng) + Formato da Inter-Mudança dos Gráficos (*.gif);;WebP ( *.webp);;Gráficos da Rede Animada Portátil (*.png *.apng) + + + + QGBA::GameBoy + + + + Autodetect + Auto-detetar + + + + Game Boy (DMG) + Game Boy (DMG) + + + + Game Boy Pocket (MGB) + Game Boy Pocket (MGB) + + + + Super Game Boy (SGB) + Super Game Boy (SGB) + + + + Super Game Boy 2 (SGB) + Super Game Boy 2 (SGB) + + + + Game Boy Color (CGB) + Game Boy Color (CGB) + + + + Game Boy Advance (AGB) + Game Boy Advance (AGB) + + + + Super Game Boy Color (SGB + CGB) + Super Game Boy Color (SGB + CGB) + + + + ROM Only + So a ROM + + + + MBC1 + MBC1 + + + + MBC2 + MBC2 + + + + MBC3 + MBC3 + + + + MBC3 + RTC + MBC3 + RTC + + + + MBC5 + MBC5 + + + + MBC5 + Rumble + MBC5 + Rumble + + + + MBC6 + MBC6 + + + + MBC7 (Tilt) + MBC7 (Inclinação) + + + + MMM01 + MMM01 + + + + HuC-1 + HuC-1 + + + + HuC-3 + HuC-3 + + + + Pocket Cam + Câmara de Bolso + + + + TAMA5 + TAMA5 + + + + Wisdom Tree + Árvore da Sabedoria + + + + NT (old 1) + NT (antigo 1) + + + + NT (old 2) + NT (antigo 2) + + + + NT (new) + NT (novo) + + + + Pokémon Jade/Diamond + Pokémon Jade/Diamond + + + + BBD + BBD + + + + Hitek + Hitek + + + + GGB-81 + GGB-81 + + + + Li Cheng + Li Cheng + + + + Sachen (MMC1) + Sachen (MMC1) + + + + Sachen (MMC2) + Sachen (MMC2) + + + + QGBA::IOViewer + + + I/O Viewer + Visualizador de E/S + + + + 0x0000 + 0x0000 + + + + + + B + B + + + + Background mode + Modo do 2º plano + + + + Mode 0: 4 tile layers + Modo 0: 4 camadas de ladrilhos + + + + Mode 1: 2 tile layers + 1 rotated/scaled tile layer + Modo 1: 2 camadas de ladrilhos + 1 camada de ladrilhos rotacionada/redimensionada + + + + Mode 2: 2 rotated/scaled tile layers + Modo 2: 2 camadas de ladrilhos rotacionadas/redimensionadas + + + + Mode 3: Full 15-bit bitmap + Modo 3: Bitmap de 15 bits completo + + + + Mode 4: Full 8-bit bitmap + Modo 4: Bitmap de 8 bits completo + + + + Mode 5: Small 15-bit bitmap + Modo 5: Bitmap de 15 bits pequeno + + + + CGB Mode + Modo CGB + + + + Frame select + Selecionar frame + + + + Unlocked HBlank + HBlank Destrancado + + + + Linear OBJ tile mapping + Mapeamento do ladrilho do OBJ linear + + + + Force blank screen + Forçar ecrã vazio + + + + Enable background 0 + Ativar o 2º plano 0 + + + + Enable background 1 + Ativar o 2º plano 1 + + + + Enable background 2 + Ativar o 2º plano 2 + + + + Enable background 3 + Ativar o 2º plano 3 + + + + Enable OBJ + Ativar OBJ + + + + Enable Window 0 + Ativar a Janela 0 + + + + Enable Window 1 + Ativar a Janela 1 + + + + Enable OBJ Window + Ativar a Janela do OBJ + + + + Swap green components + Trocar componentes verdes + + + + Currently in VBlank + Atualmente no VBlank + + + + Currently in HBlank + Atualmente no HBlank + + + + Currently in VCounter + Atualmente no VCounter + + + + Enable VBlank IRQ generation + Ativar geração do IRQ VBlank + + + + Enable HBlank IRQ generation + Ativar geração do IRQ HBlank + + + + Enable VCounter IRQ generation + Ativar geração do IRQ VCounter + + + + VCounter scanline + Scanline do VCounter + + + + Current scanline + Scanline atual + + + + + + + Priority + Prioridade + + + + + + + Tile data base (* 16kB) + Banco de dados dos ladrilhos (* 16 kBs) + + + + + + + Enable mosaic + Ativar o mosaico + + + + + + + Enable 256-color + Ativar 256 cores + + + + + + + Tile map base (* 2kB) + Base do mapa dos ladrilhos (* 2 kBs) + + + + + + + Background dimensions + Dimensões do 2º plano + + + + + Overflow wraps + Embrulhos do excesso + + + + + + + + + Horizontal offset + Deslocamento horizontal + + + + + + + + + Vertical offset + Deslocamento vertical + + + + + + + + + + + + + + + Fractional part + Parte fracionária + + + + + + + + + + + Integer part + Parte inteira + + + + + + + Integer part (low) + Parte inteira (baixa) + + + + + + + Integer part (high) + Parte inteira (alta) + + + + + End x + Final x + + + + + Start x + X inicial + + + + + End y + Final y + + + + + Start y + Y inicial + + + + Window 0 enable BG 0 + Janela 0 ativar BG 0 + + + + Window 0 enable BG 1 + Janela 0 ativar BG 1 + + + + Window 0 enable BG 2 + Janela 0 ativar BG 2 + + + + Window 0 enable BG 3 + Janela 0 ativar BG 3 + + + + Window 0 enable OBJ + Janela 0 ativar OBJ + + + + Window 0 enable blend + Janela 0 ativar a mistura + + + + Window 1 enable BG 0 + Janela 1 ativar BG 0 + + + + Window 1 enable BG 1 + Janela 1 ativar BG 1 + + + + Window 1 enable BG 2 + Janela 1 ativar BG 2 + + + + Window 1 enable BG 3 + Janela 1 ativar BG 3 + + + + Window 1 enable OBJ + Janela 1 ativar OBJ + + + + Window 1 enable blend + Janela 1 ativar a mistura + + + + Outside window enable BG 0 + Fora da janela ativar BG 0 + + + + Outside window enable BG 1 + Fora da janela ativar BG 1 + + + + Outside window enable BG 2 + Fora da janela ativar BG 2 + + + + Outside window enable BG 3 + Fora da janela ativar BG 3 + + + + Outside window enable OBJ + Fora da janela ativar OBJ + + + + Outside window enable blend + Fora da janela ativar a mistura + + + + OBJ window enable BG 0 + Janela do OBJ ativar BG 0 + + + + OBJ window enable BG 1 + Janela do OBJ ativar BG 1 + + + + OBJ window enable BG 2 + Janela do OBJ ativar BG 2 + + + + OBJ window enable BG 3 + Janela do OBJ ativar BG 3 + + + + OBJ window enable OBJ + Janela do OBJ ativar OBJ + + + + OBJ window enable blend + Janela do OBJ ativar a mistura + + + + Background mosaic size vertical + Tamanho vertical do mosaico do 2º plano + + + + Background mosaic size horizontal + Tamanho horizontal do mosaico do 2º plano + + + + Object mosaic size vertical + Tamanho vertical do mosaico dos objetos + + + + Object mosaic size horizontal + Tamanho horizontal do mosaico dos objetos + + + + BG 0 target 1 + BG 0 alvo 1 + + + + BG 1 target 1 + BG 1 alvo 1 + + + + BG 2 target 1 + BG 2 alvo 1 + + + + BG 3 target 1 + BG 3 alvo 1 + + + + OBJ target 1 + Alvo do OBJ 1 + + + + Backdrop target 1 + Alvo do 2º plano 1 + + + + Blend mode + Modo de mistura + + + + Disabled + Desativado + + + + Additive blending + Mistura aditiva + + + + Brighten + Clarear + + + + Darken + Escurecer + + + + BG 0 target 2 + BG 0 alvo 2 + + + + BG 1 target 2 + BG 1 alvo 2 + + + + BG 2 target 2 + BG 2 alvo 2 + + + + BG 3 target 2 + BG 3 alvo 2 + + + + OBJ target 2 + Alvo do OBJ 2 + + + + Backdrop target 2 + Alvo do 2º plano 2 + + + + Blend A (target 1) + Mistura A (alvo 1) + + + + Blend B (target 2) + Mistura B (alvo 2) + + + + Blend Y + Mistura Y + + + + + Sweep shifts + Trocas de varredura + + + + + Sweep subtract + Subtrair varredura + + + + + Sweep time (in 1/128s) + Tempo da varredura (em 1/128s) + + + + + + + + + + + Sound length + Comprimento do som + + + + + + + Duty cycle + Ciclo do dever + + + + + + + + + Envelope step time + Tempo do passo do envelope + + + + + + + + + Envelope increase + Aumentar envelope + + + + + + + + + Initial volume + Volume inicial + + + + + + Sound frequency + Frequência do som + + + + + + + + + + + Timed + Programado + + + + + + + + + + + Reset + Resetar + + + + Double-size wave table + Tabela da onda com tamanho duplo + + + + Active wave table + Tabela de som ativa + + + + + Enable channel 3 + Ativar canal 3 + + + + + Volume + Volume + + + + + 0% + 0% + + + + + + 100% + 100% + + + + + + 50% + 50% + + + + + + 25% + 25% + + + + + + + 75% + 75% + + + + + Clock divider + Divisor de relógio + + + + + Register stages + Estágios do registo + + + + + 15 + 15 + + + + + 7 + 7 + + + + + Shifter frequency + Frequência do deslocador + + + + PSG volume right + Volume do PSG direito + + + + PSG volume left + Volume do PSG esquerdo + + + + + Enable channel 1 right + Ativar canal 1 a direita + + + + + Enable channel 2 right + Ativar canal 2 a direita + + + + + Enable channel 3 right + Ativar canal 3 a direita + + + + + Enable channel 4 right + Ativar canal 4 a direita + + + + + Enable channel 1 left + Ativar canal 1 a esquerda + + + + + Enable channel 2 left + Ativar canal 2 a esquerda + + + + + Enable channel 3 left + Ativar canal 3 a esquerda + + + + + Enable channel 4 left + Ativar canal 4 a esquerda + + + + PSG master volume + Volume mestre do PSG + + + + Loud channel A + Canal A alto + + + + Loud channel B + Canal B alto + + + + Enable channel A right + Ativar canal A a direita + + + + Enable channel A left + Ativar canal A a esquerda + + + + Channel A timer + Cronômetro do canal A + + + + + 0 + 0 + + + + + + + + + + + + 1 + 1 + + + + Channel A reset + Resetar canal A + + + + Enable channel B right + Ativar canal B a direita + + + + Enable channel B left + Ativar canal B a esquerda + + + + Channel B timer + Cronômetro do canal B + + + + Channel B reset + Resetar canal B + + + + + Active channel 1 + Canal ativo 1 + + + + + Active channel 2 + Canal ativo 2 + + + + + Active channel 3 + Canal ativo 3 + + + + + Active channel 4 + Canal ativo 4 + + + + + Enable audio + Ativar áudio + + + + Bias + Viés + + + + Resolution + Resolução + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample + Amostra + + + + + + + + + + + Address (low) + Endereço (baixo) + + + + + + + + + + + Address (high) + Endereço (alto) + + + + + + Sound frequency (low) + Frequência do som (baixo) + + + + + + Sound frequency (high) + Frequência do som (alto) + + + + Source (high) + Fonte (alta) + + + + Source (low) + Fonte (baixa) + + + + Destination (high) + Destinação (alta) + + + + Destination (low) + Destinação (baixa) + + + + + Green (low) + Verde (baixo) + + + + + Green (high) + Verde (alto) + + + + + + + Word count + Contagem de palavras + + + + + + + Destination offset + Deslocamento do destino + + + + + + + + + + + Increment + Incrementar + + + + + + + + + + + Decrement + Decréscimo + + + + + + + + + + + Fixed + Consertado + + + + + + + Increment and reload + Incrementar e recarregar + + + + + + + Source offset + Deslocamento da fonte + + + + + + + Repeat + Repetir + + + + + + + 32-bit + 32 bits + + + + + + + Start timing + Iniciar timing + + + + + + + + Immediate + Imediato + + + + + + + + + + + VBlank + VBlank + + + + + + + + + + HBlank + HBlank + + + + + + + + + + + + IRQ + IRQ + + + + + + + + + + + + + + Enable + Ativar + + + + + + Audio FIFO + Áudio do FIFO + + + + Video Capture + Captura de Vídeo + + + + DRQ + DRQ + + + + + + + + + + + Value + Valor + + + + + + + Scale + Escala + + + + + + + + 1/64 + 1/64 + + + + + + + + 1/256 + 1/256 + + + + + + + + 1/1024 + 1/1024 + + + + + + Cascade + Em cascata + + + + + A + A + + + + + Select + Select + + + + + Start + Start + + + + + Right + Direita + + + + + Left + Esquerda + + + + + Up + Para cima + + + + + Down + Para baixo + + + + + R + R + + + + + L + L + + + + Condition + Condição + + + + SC + SC + + + + SD + SD + + + + SI + SI + + + + SO + SO + + + + + VCounter + VCounter + + + + + Timer 0 + Cronômetro 0 + + + + + Timer 1 + Cronômetro 1 + + + + + Timer 2 + Cronômetro 2 + + + + + Timer 3 + Cronômetro 3 + + + + + SIO + SIO + + + + + DMA 0 + DMA 0 + + + + + DMA 1 + DMA 1 + + + + + DMA 2 + DMA 2 + + + + + DMA 3 + DMA 3 + + + + + Keypad + Keypad + + + + + Gamepak + Gamepak + + + + SRAM wait + Espera do SRAM + + + + + + + + 4 + 4 + + + + + + + 3 + 3 + + + + + + + + 2 + 2 + + + + + + + + 8 + 8 + + + + Cart 0 non-sequential + Cartucho 0 não-sequencial + + + + Cart 0 sequential + Cartucho 0 sequencial + + + + Cart 1 non-sequential + Cartucho 1 não-sequencial + + + + Cart 1 sequential + Cartucho 1 sequencial + + + + Cart 2 non-sequential + Cartucho 2 não-sequencial + + + + Cart 2 sequential + Cartucho 2 sequencial + + + + PHI terminal + Terminal do PHI + + + + + Disable + Desativar + + + + 4.19MHz + 4.19 MHz + + + + 8.38MHz + 8.38 MHz + + + + 16.78MHz + 16.78 MHz + + + + Gamepak prefetch + Pré-carga do Gamepak + + + + Enable IRQs + Ativar IRQs + + + + Right/A + Direita/A + + + + Left/B + Esquerda/B + + + + Up/Select + Para cima/Select + + + + Down/Start + Para baixo/Start + + + + Active D-pad + D-pad Ativo + + + + Active face buttons + Botões de face ativos + + + + Internal clock + Relógio interno + + + + 32× clocking (CGB only) + 32x o clock (só no GBC) + + + + Transfer active + Transferência ativa + + + + Divider + Divisor + + + + 1/16 + 1/16 + + + + + LCD STAT + STAT do LCD + + + + + Timer + Cronômetro + + + + + Serial + Série + + + + + Joypad + Joypad + + + + Volume right + Volume direito + + + + Output right + Saída direita + + + + Volume left + Volume esquerdo + + + + Output left + Saída esquerda + + + + Background enable/priority + Ativar/prioridade do 2º plano + + + + Enable sprites + Ativar imagens móveis + + + + Double-height sprites + Imagens móveis com dobro da altura + + + + Background tile map + Mapa dos ladrilhos do 2º plano + + + + + 0x9800 – 0x9BFF + 0x9800 – 0x9BFF + + + + + 0x9C00 – 0x9FFF + 0x9C00 – 0x9FFF + + + + Background tile data + Dados dos ladrilhos do 2º plano + + + + 0x8800 – 0x87FF + 0x8800 – 0x87FF + + + + 0x8000 – 0x8FFF + 0x8000 – 0x8FFF + + + + Enable window + Ativar janela + + + + Window tile map + Mapa dos ladrilhos da janela + + + + Enable LCD + Ativar LCD + + + + Mode + Modo + + + + 0: HBlank + 0: HBlank + + + + 1: VBlank + 1: VBlank + + + + 2: OAM scan + 2: Scan do OAM + + + + 3: HDraw + 3: HDraw + + + + In LYC + Em LYC + + + + Enable HBlank (mode 0) IRQ + Ativar IRQ do HBlank (modo 0) + + + + Enable VBlank (mode 1) IRQ + Ativar IRQ do VBlank (modo 1) + + + + Enable OAM (mode 2) IRQ + Ativar IRQ do OAM (modo 2) + + + + Enable LYC IRQ + Ativar IRQ do LYC + + + + Current Y coordinate + Coordenada Y atual + + + + Comparison Y coordinate + Comparação da coordenada Y + + + + Start upper byte + Iniciar byte superior + + + + + + Color 0 shade + Tom da cor 0 + + + + + + Color 1 shade + Tom da cor 1 + + + + + + Color 2 shade + Tom da cor 2 + + + + + + Color 3 shade + Tom da cor 3 + + + + Prepare to switch speed + Preparar para trocar a velocidade + + + + Double speed + Velocidade dupla + + + + VRAM bank + Banco do VRAM + + + + Length + Comprimento + + + + Timing + Cronometragem + + + + Write bit + Bit da gravação + + + + Read bit + Bit de leitura + + + + + Unknown + Desconhecido + + + + + Current index + Índice atual + + + + + Auto-increment + Auto-incrementar + + + + + Red + Vermelho + + + + + Blue + Azul + + + + Sprite ordering + Ordenação das imagens móveis + + + + OAM order + Ordem da OAM + + + + x coordinate sorting + Organização da coordenada X + + + + WRAM bank + Banco do WRAM + + + + QGBA::KeyEditor + + + + --- + --- + + + + QGBA::LibraryTree + + + Name + Nome + + + + Location + Local + + + + Platform + Plataforma + + + + Size + Tamanho + + + + CRC32 + CRC32 + + + + QGBA::LoadSaveState + + + + %1 State + Estado %1 + + + + + + + + + + + + No Save + Nenhum Save + + + + 5 + 5 + + + + 6 + 6 + + + + 8 + 8 + + + + 4 + 4 + + + + 1 + 1 + + + + 3 + 3 + + + + 7 + 7 + + + + 9 + 9 + + + + 2 + 2 + + + + Cancel + Cancelar + + + + Load State + Carregar o State + + + + Save State + Gravar o State + + + + Empty + Vazio + + + + Corrupted + Corrompido + + + + Slot %1 + Slot %1 + + + + QGBA::LogConfigModel + + + + Default + Padrão + + + + Fatal + Fatal + + + + Error + Erro + + + + Warning + Aviso + + + + Info + Info + + + + Debug + Debug + + + + Stub + Stub + + + + Game Error + Erro do Jogo + + + + QGBA::LogController + + + [%1] %2: %3 + [%1] %2: %3 + + + + An error occurred + Um erro ocorreu + + + + DEBUG + DEBUG + + + + STUB + STUB + + + + INFO + INFO + + + + WARN + AVISAR + + + + ERROR + ERRO + + + + FATAL + FATAL + + + + GAME ERROR + ERRO DO JOGO + + + + QGBA::LogView + + + Logs + Registos + + + + Enabled Levels + Níveis Ativados + + + + Debug + Debug + + + + Stub + Stub + + + + Info + Informações + + + + Warning + Aviso + + + + Error + Erro + + + + Fatal + Fatal + + + + Game Error + Erro do Jogo + + + + Advanced settings + Configurações avançadas + + + + Clear + Limpar + + + + Max Lines + Máximo de Linhas + + + + QGBA::MapView + + + Maps + Mapas + + + + Magnification + Ampliação + + + + Export + Exportar + + + + Copy + Copiar + + + + Priority + Prioridade + + + + + Map base + Base do mapa + + + + + Tile base + Base dos ladrilhos + + + + Size + Tamanho + + + + + Offset + Deslocamento + + + + Xform + Xform + + + + Map Addr. + Endereço do Mapa. + + + + Mirror + Espelho + + + + None + Nenhum + + + + Both + Ambos + + + + Horizontal + Horizontal + + + + Vertical + Vertical + + + + + + N/A + N/D + + + + Export map + Exportar mapa + + + + Portable Network Graphics (*.png) + Gráficos Portáteis da Rede (*.png) + + + + QGBA::MemoryDump + + + Save Memory Range + Gravar o Alcance da Memória + + + + Start Address: + Endereço Inicial: + + + + Byte Count: + Contagem dos Bytes: + + + + Dump across banks + Dumpar através dos bancos + + + + Save memory region + Gravar a região da memória + + + + Failed to open output file: %1 + Falha ao abrir o ficheiro de saída: %1 + + + + QGBA::MemoryModel + + + Copy selection + Copiar seleção + + + + Save selection + Gravar seleção + + + + Paste + Colar + + + + Load + Carregar + + + + All + Todos + + + + Load TBL + Carregar TBL + + + + Save selected memory + Gravar a memória selecionada + + + + Failed to open output file: %1 + Falha ao abrir o ficheiro de saída: %1 + + + + Load memory + Carregar memória + + + + Failed to open input file: %1 + Falha ao abrir o ficheiro de entrada: %1 + + + + TBL + TBL + + + + ISO-8859-1 + ISO-8859-1 + + + + QGBA::MemorySearch + + + Memory Search + Busca na Memória + + + + Address + Endereço + + + + Current Value + Valor Atual + + + + + Type + Tipo + + + + Value + Valor + + + + Numeric + Numérico + + + + Text + Texto + + + + Width + Largura + + + + + Guess + Palpite + + + + 1 Byte (8-bit) + 1 Byte (8 bits) + + + + 2 Bytes (16-bit) + 2 Bytes (16 bits) + + + + 4 Bytes (32-bit) + 4 Bytes (32 bits) + + + + Number type + Tipo de número + + + + Decimal + Decimal + + + + Hexadecimal + Hexadecimal + + + + Search type + Tipo de busca + + + + Equal to value + Igual ao valor + + + + Greater than value + Maior do que o valor + + + + Less than value + Menor do que o valor + + + + Unknown/changed + Desconhecido/mudado + + + + Changed by value + Mudado pelo valor + + + + Unchanged + Sem mudança + + + + Increased + Aumentado + + + + Decreased + Diminuído + + + + Search ROM + Procurar na ROM + + + + New Search + Nova Busca + + + + Search Within + Procurar por Dentro + + + + Open in Memory Viewer + Abrir no Visualizador de Memória + + + + Refresh + Atualizar + + + + (%0/%1×) + (%0/%1×) + + + + (⅟%0×) + (⅟%0×) + + + + (%0×) + (%0×) + + + + %1 byte%2 + %1 byte%2 + + + + QGBA::MemoryView + + + Memory + Memória + + + + Inspect Address: + Inspecionar Endereço: + + + + Set Alignment: + Definir Alinhamento: + + + + &1 Byte + &1 Byte + + + + &2 Bytes + &2 Bytes + + + + &4 Bytes + &4 Bytes + + + + Unsigned Integer: + Inteiro não Assinado: + + + + Signed Integer: + Inteiro com Sinal: + + + + String: + Texto: + + + + Load TBL + Carregar TBL + + + + Copy Selection + Copiar Seleção + + + + Paste + Colar + + + + Save Selection + Gravar Seleção + + + + Save Range + Gravar Alcance + + + + Load + Carregar + + + + QGBA::MessagePainter + + + Frame %1 + Frame %1 + + + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + + + QGBA::ObjView + + + Sprites + Imagens Móveis + + + + Address + Endereço + + + + Copy + Copiar + + + + Magnification + Ampliação + + + + Geometry + Geometria + + + + Position + Posição + + + + Dimensions + Dimensões + + + + Matrix + Matriz + + + + Export + Exportar + + + + Attributes + Atributos + + + + Transform + Transformar + + + + + Off + Desligado + + + + Palette + Paleta + + + + Double Size + Tamanho Duplo + + + + + + Return, Ctrl+R + Retornar, Ctrl+R + + + + Flipped + Invertido + + + + H + Short for horizontal + H + + + + V + Short for vertical + V + + + + Mode + Modo + + + + + Normal + Normal + + + + Mosaic + Mosaico + + + + Enabled + Ativado + + + + Priority + Prioridade + + + + Tile + Ladrilho + + + + + 0x%0 + 0x%0 + + + + + + + + + + + --- + --- + + + + Trans + Trans + + + + OBJWIN + OBJWIN + + + + Invalid + Inválido + + + + + N/A + N/D + + + + Export sprite + Exportar imagem móvel + + + + Portable Network Graphics (*.png) + Gráficos Portáteis da Rede (*.png) + + + + QGBA::OverrideView + + + Game Overrides + Substituições do Jogo + + + + Game Boy Advance + Game Boy Advance + + + + + + + Autodetect + Auto-detetar + + + + Realtime clock + Relógio em tempo real + + + + Gyroscope + Giroscópio + + + + Tilt + Inclinação + + + + Light sensor + Sensor de luz + + + + Rumble + Rumble + + + + Save type + Tipo de save + + + + None + Nenhum + + + + SRAM + SRAM + + + + Flash 512kb + Flash de 512 kbs + + + + Flash 1Mb + Flash de 1 Mb + + + + EEPROM 8kB + EEPROM de 8 kBs + + + + EEPROM 512 bytes + EEPROM de 512 bytes + + + + SRAM 64kB (bootlegs only) + SRAM de 64 kBs (só bootlegs) + + + + Idle loop + Repetição inativa + + + + Game Boy Player features + Funções do Game Boy Player + + + + VBA bug compatibility mode + Modo de compatibilidade dos bugs do VBA + + + + Game Boy + Game Boy + + + + Game Boy model + Modelo do Game Boy + + + + Memory bank controller + Controle do banco de memória + + + + Background Colors + Cores do 2º Plano + + + + Sprite Colors 1 + Cores da Imagem Móvel 1 + + + + Sprite Colors 2 + Cores da Imagem Móvel 2 + + + + Palette preset + Pré-definições da paleta + + + + Official MBCs + MBCs oficiais + + + + Licensed MBCs + MBCs licenciados + + + + Unlicensed MBCs + MBCs não licenciados + + + + QGBA::PaletteView + + + Palette + Paleta + + + + Background + 2º plano + + + + Objects + Objetos + + + + Selection + Seleção + + + + Red + Vermelho + + + + Green + Verde + + + + Blue + Azul + + + + 16-bit value + Valor de 16 bits + + + + Hex code + Código hexadecimal + + + + Palette index + Indice da paleta + + + + Export BG + Exportar BG + + + + Export OBJ + Exportar OBJ + + + + #%0 + #%0 + + + + 0x%0 + 0x%0 + + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + Export palette + Exportar paleta + + + + Windows PAL (*.pal);;Adobe Color Table (*.act) + Windows PAL (*.pal);;Tabela de Cores da Adobe (*.act) + + + + Failed to open output palette file: %1 + Falha ao abrir o ficheiro de saída da paleta: %1 + + + + QGBA::PlacementControl + + + Adjust placement + Ajustar posicionamento + + + + All + Tudo + + + + Offset + Deslocamento + + + + X + X + + + + Y + Y + + + + QGBA::PrinterView + + + Game Boy Printer + Impressora do Game Boy + + + + Hurry up! + Apresse-se! + + + + Tear off + Rasgar + + + + Magnification + Ampliação + + + + Copy + Copiar + + + + Save Printout + Gravar impressão + + + + Portable Network Graphics (*.png) + Gráficos Portáteis da Rede (*.png) + + + + QGBA::ROMInfo + + + + + + + (unknown) + (desconhecido) + + + + bytes + bytes + + + + (no database present) + (nenhum banco de dados presente) + + + + ROM Info + Informações da ROM + + + + Game name: + Nome do jogo: + + + + Internal name: + Nome interno: + + + + Game ID: + ID do Jogo: + + + + File size: + Tamanho do ficheiro: + + + + CRC32: + CRC32: + + + + Save file: + + + + + QGBA::ReportView + + + Bug report archive + Arquivo do relatório dos bugs + + + + ZIP archive (*.zip) + Arquivo ZIP (*.zip) + + + + Generate Bug Report + Gerar Relatório do Bug + + + + <html><head/><body><p>To file a bug report, please first generate a report file to attach to the bug report you're about to file. It is recommended that you include the save files, as these often help with debugging issues. This will collect some information about the version of {projectName} you're running, your configuration, your computer, and the game you currently have open (if any). Once this collection is completed you can review all of the information gathered below and save it to a zip file. The collection will automatically attempt to redact any personal information, such as your username if it's in any of the paths gathered, but just in case you can edit it afterwards. After you have generated and saved it, please click the button below or go to <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> to file the bug report on GitHub. Make sure to attach the report you generated!</p></body></html> + <html><head/><body><p>Para registar um relatório de bug comece por gerar um ficheiro de relatório para anexar ao relatório de bug que está prestes a enviar. É recomendável incluir os ficheiros save, porque geralmente ajudam com problemas de depuração. Isso coletará algumas informações sobre a versão do {projectName} que executa, a sua configuração, o seu computador e o jogo que está aberto no momento (se houver). Assim que esta colheita estiver concluída, poderá rever todas as informações coletadas abaixo e gravá-las num ficheiro zip. A colheita tentará redigir automaticamente qualquer informação pessoal, como o seu nome de utilizador, se estiver em algum dos caminhos coletados, mas pode editá-lo posteriormente. Após gerá-lo e gravá-lo, clique no botão abaixo ou vá para <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> para registar o relatório de bug no GitHub. Certifique-se de anexar o relatório que gerou!</p></body></html> + + + + Generate report + Gerar relatório + + + + Save + Gravar + + + + Open issue list in browser + Abrir lista de problemas no navegador + + + + Include save file + Incluir ficheiro do save + + + + Create and include savestate + Criar e incluir savestate + + + + QGBA::SaveConverter + + + Save games and save states (%1) + Saves dos jogos e save states (%1) + + + + Select save game or save state + Selecione o save do jogo ou save state + + + + Save games (%1) + Saves dos jogos (%1) + + + + Select save game + Selecione o save do jogo + + + + Conversion failed + A conversão falhou + + + + Failed to convert the save game. This is probably a bug. + Falhou em converter o save do jogo. Isto é provavelmente um bug. + + + + No file selected + Nenhum ficheiro selecionado + + + + Could not open file + Não pôde abrir o ficheiro + + + + No valid formats found + Não foram encontrados formatos válidos + + + + Please select a valid input file + Por favor selecione um ficheiro de entrada válido + + + + No valid conversions found + Não foram encontradas conversões válidas + + + + Cannot convert save games between platforms + Não pôde converter os saves do jogo entre as plataformas + + + + Convert/Extract Save Game + Converter/Extrair o Save do Jogo + + + + Input file + Ficheiro de entrada + + + + + Browse + Explorar + + + + Output file + Ficheiro de saída + + + + %1 %2 save game + %1 %2 save do jogo + + + + little endian + little endian + + + + big endian + big endian + + + + SRAM + SRAM + + + + %1 flash + %1 flash + + + + %1 EEPROM + %1 EEPROM + + + + + RTC + + + + + %1 SRAM + RTC + %1 SRAM + RTC + + + + %1 SRAM + %1 SRAM + + + + packed MBC2 + empacotou o MBC2 + + + + unpacked MBC2 + desempacotou o MBC2 + + + + MBC6 flash + Flash do MBC6 + + + + MBC6 combined SRAM + flash + MBC6 SRAM combinado + flash + + + + MBC6 SRAM + SRAM do MBC6 + + + + TAMA5 + TAMA5 + + + + %1 (%2) + %1 (%2) + + + + %1 save state with embedded %2 save game + %1 save state com %2 saves do jogo embutido + + + + %1 SharkPort %2 save game + %1 SharkPort %2 save do jogo + + + + %1 GameShark Advance SP %2 save game + %1 GameShark Advance SP %2 save do jogo + + + + QGBA::ScriptingTextBuffer + + + Untitled buffer + Buffer sem título + + + + QGBA::ScriptingView + + + Scripting + Scripting + + + + Run + Executar + + + + File + Ficheiro + + + + Load recent script + Carregar script recente + + + + Load script... + Carregar script... + + + + &Reset + &Resetar + + + + 0 + 0 + + + + Select script to load + Selecione o script a carregar + + + + Lua scripts (*.lua) + Scripts do lua (*.lua) + + + + All files (*.*) + Todos os ficheiros (*.*) + + + + QGBA::SensorView + + + Sensors + Sensores + + + + Realtime clock + Relógio em tempo real + + + + Fixed time + Tempo fixo + + + + System time + Horário do sistema + + + + Start time at + Horário do início em + + + + Now + Agora + + + + Offset time + Tempo do deslocamento + + + + sec + segs + + + + MM/dd/yy hh:mm:ss AP + MM/dd/aa hh:mm:ss AP + + + + Light sensor + Sensor de luz + + + + Brightness + Brilho + + + + Tilt sensor + Sensor de inclinação + + + + + Set Y + Definir Y + + + + + Set X + Definir X + + + + Gyroscope + Giroscópio + + + + Sensitivity + Sensibilidade + + + + QGBA::SettingsView + + + + Qt Multimedia + Multimídia do Qt + + + + SDL + SDL + + + + Software (Qt) + Software (Qt) + + + + + OpenGL + OpenGL + + + + OpenGL (force version 1.x) + OpenGL (forçar a versão 1.x) + + + + None + Nenhum + + + + None (Still Image) + Nenhum (Imagem Parada) + + + + Keyboard + Teclado + + + + Controllers + Controles + + + + Shortcuts + Atalhos + + + + + Shaders + Shaders + + + + Select BIOS + Selecionar BIOS + + + + Select directory + Selecione o diretório + + + + Select image + Selecionar imagem + + + + Image file (*.png *.jpg *.jpeg) + Ficheiro da imagem (*.png *.jpg *.jpeg) + + + + (%1×%2) + (%1×%2) + + + + Never + Nunca + + + + Just now + Aconteceu agora + + + + Less than an hour ago + Menos do que uma hora atrás + + + + %n hour(s) ago + + %n hora atrás + %n horas atrás + + + + + %n day(s) ago + + %n dia atrás + %n dias atrás + + + + + Settings + Configurações + + + + Audio/Video + Áudio/Vídeo + + + + Gameplay + Jogabilidade + + + + Interface + Interface + + + + Update + Atualizar + + + + Emulation + Emulação + + + + Enhancements + Melhorias + + + + BIOS + BIOS + + + + Paths + Caminhos + + + + Logging + Registos + + + + Game Boy + Game Boy + + + + Audio driver: + Driver de áudio: + + + + Audio buffer: + Buffer do áudio: + + + + + 1536 + 1536 + + + + 512 + 512 + + + + 768 + 768 + + + + 1024 + 1024 + + + + 2048 + 2048 + + + + 3072 + 3072 + + + + 4096 + 4096 + + + + samples + Amostras + + + + Sample rate: + Taxa das amostras: + + + + + 44100 + 44100 + + + + 22050 + 22050 + + + + 32000 + 32000 + + + + 48000 + 48000 + + + + Hz + Hz + + + + Volume: + Volume: + + + + + + + Mute + Mudo + + + + Fast forward volume: + Avanço rápido do volume: + + + + Audio in multiplayer: + Áudio no multiplayer: + + + + All windows + Todas as janelas + + + + Player 1 window only + Só a janela do jogador 1 + + + + Currently active player window + Atualmente na janela do jogador ativo + + + + Display driver: + Driver de vídeo: + + + + Frameskip: + Frameskip: + + + + Skip every + Ignorar a cada + + + + + frames + frames + + + + FPS target: + FPS alvo: + + + + frames per second + Frames por segundo + + + + Sync: + Sincronizar: + + + + + Video + Vídeo + + + + + Audio + Áudio + + + + Lock aspect ratio + Travar a proporção do aspeto + + + + Force integer scaling + Forçar o dimensionamento do inteiro + + + + Bilinear filtering + Filtragem bilinear + + + + Show filename instead of ROM name in library view + Mostrar o nome do ficheiro ao invés do nome da ROM na visualização da biblioteca + + + + + Pause + Pausar + + + + When inactive: + Quando inativo: + + + + On loading a game: + Ao carregar um jogo: + + + + Load last state + Carregar o último state + + + + Load cheats + Carregar trapaças + + + + Save entered cheats + Gravar as trapaças inseridas + + + + When minimized: + Quando minimizado: + + + + Current channel: + Canal atual: + + + + Current version: + Versão atual: + + + + Update channel: + Canal da atualização: + + + + Available version: + Versão disponível: + + + + (Unknown) + (Desconhecido) + + + + Last checked: + Verificado pela última vez: + + + + Automatically check on start + Verificar automaticamente ao iniciar + + + + Check now + Verificar agora + + + + Default color palette only + Só a cor padrão da paleta + + + + SGB color palette if available + Paleta das cores do SGB se disponível + + + + GBC color palette if available + Paleta das cores do GBC se disponível + + + + SGB (preferred) or GBC color palette if available + SGB (preferido) ou paleta das cores do GBC se disponível + + + + Game Boy Camera + Câmara do Game Boy + + + + Driver: + Driver: + + + + Source: + Fonte: + + + + Native (59.7275) + Nativo (59,7275) + + + + Interframe blending + Mistura do interframe + + + + Language + Idioma + + + + Library: + Biblioteca: + + + + List view + Visualização em lista + + + + Tree view + Visualização em árvore + + + + Show when no game open + Mostrar quando nenhum jogo estiver aberto + + + + Clear cache + Limpar cache + + + + Allow opposing input directions + Permitir direções de entrada opostas + + + + Suspend screensaver + Suspender a proteção de ecrã + + + + Dynamically update window title + Atualizar título da janela dinamicamente + + + + Show filename instead of ROM name in title bar + Mostrar o nome do fiheiro ao invés do nome da ROM na barra de título + + + + Show OSD messages + Mostrar mensagens do OSD + + + + Enable Discord Rich Presence + Ativar a Presença Rica do Discord + + + + Periodically autosave state + Auto-gravar o state periodicamente + + + + Show FPS in title bar + Mostrar o FPS na barra do título + + + + Show frame count in OSD + Mostrar contagem dos frames no OSD + + + + Show emulation info on reset + Mostrar informações da emulação ao resetar + + + + Custom border: + + + + + Fast forward speed: + Velocidade do avanço rápido: + + + + + Unbounded + Ilimitado + + + + Fast forward (held) speed: + Velocidade do avanço rápido (pressionado): + + + + Autofire interval: + Intervalo do auto-disparo: + + + + Enable rewind + Ativar retrocesso + + + + Rewind history: + Histórico do retrocesso: + + + + Rewind speed: + + + + + Idle loops: + Repetições inativas: + + + + Run all + Executar todos + + + + Remove known + Remover conhecidos + + + + Detect and remove + Detetar e remover + + + + Preload entire ROM into memory + Pré-carregar a ROM inteira na memória + + + + Save state extra data: + Dados extras do save state: + + + + + Save game + Save do jogo + + + + Load state extra data: + Carregar dados extras do state: + + + + Models + Modelos + + + + GB only: + Só para o GB: + + + + SGB compatible: + Compatível com o SGB: + + + + GBC only: + Só para o GBC: + + + + GBC compatible: + Compatível com o GBC: + + + + SGB and GBC compatible: + Compatível com o SGB e o GBC: + + + + Game Boy palette + Paleta do Game Boy + + + + Preset: + Pré-definições: + + + + + Screenshot + Screenshot + + + + + Cheat codes + Códigos de trapaça + + + + Enable Game Boy Player features by default + Ativar funções do Game Boy Player por padrão + + + + Enable VBA bug compatibility in ROM hacks + Ativar compatibilidade dos bugs do VBA nos hacks das ROMs + + + + Video renderer: + Renderizador do vídeo: + + + + Software + Software + + + + OpenGL enhancements + Melhorias do OpenGL + + + + High-resolution scale: + Escala de alta-resolução: + + + + (240×160) + (240×160) + + + + XQ GBA audio (experimental) + Áudio do XQ GBA (experimental) + + + + GB BIOS file: + Ficheiro da BIOS do GB: + + + + + + + + + + + + + Browse + Explorar + + + + Use BIOS file if found + Usar o ficheiro da BIOS se encontrado + + + + Skip BIOS intro + Ignorar a introdução da BIOS + + + + GBA BIOS file: + Ficheiro da BIOS do GBA: + + + + GBC BIOS file: + Ficheiro da BIOS do GBC: + + + + SGB BIOS file: + Ficheiro da BIOS do SGB: + + + + Save games + Saves dos jogos + + + + + + + + Same directory as the ROM + O mesmo diretório que a ROM + + + + Save states + Save states + + + + Screenshots + Screenshots + + + + Patches + Patches + + + + Cheats + Trapaças + + + + Log to file + Registar ao ficheiro + + + + Log to console + Registar à console + + + + Select Log File + Selecionar Ficheiro de Registo + + + + Default BG colors: + Cores padrão do 2º plano: + + + + Default sprite colors 1: + Cores padrão da imagem móvel 1: + + + + Default sprite colors 2: + Cores padrão da imagem móvel 2: + + + + Super Game Boy borders + Bordas do Super Game Boy + + + + QGBA::ShaderSelector + + + No shader active + Nenhum shader ativo + + + + + Load shader + Carregar shader + + + + No shader loaded + Nenhum shader carregado + + + + by %1 + por %1 + + + + Preprocessing + Pré-processamento + + + + Pass %1 + Passe %1 + + + + Shaders + Shaders + + + + Active Shader: + Shader Ativo: + + + + Name + Nome + + + + Author + Autor + + + + Description + Descrição + + + + Unload Shader + Descarregar Shader + + + + Load New Shader + Carregar Novo Shader + + + + QGBA::ShortcutModel + + + Action + Ação + + + + Keyboard + Teclado + + + + Gamepad + Controle + + + + QGBA::ShortcutView + + + Edit Shortcuts + Editar Atalhos + + + + Keyboard + Teclado + + + + Gamepad + Controle + + + + Clear + Limpar + + + + QGBA::TileView + + + Export tiles + Exportar ladrilhos + + + + + Portable Network Graphics (*.png) + Gráficos Portáteis da Rede (*.png) + + + + Export tile + Exportar ladrilho + + + + Tiles + Ladrilhos + + + + Export Selected + Exportar Selecionado + + + + Export All + Exportar Tudo + + + + 256 colors + 256 cores + + + + Palette + Paleta + + + + Magnification + Ampliação + + + + Tiles per row + Ladrilhos por linha + + + + Fit to window + Encaixar na janela + + + + Displayed tiles + Mosaicos exibidos + + + + Only BG tiles + Só os mosaicos do 2º plano + + + + Only OBJ tiles + Só os mosaicos do OBJ + + + + Both + Ambos + + + + Copy Selected + Copiar o Selecionado + + + + Copy All + Copiar Tudo + + + + QGBA::VideoView + + + Failed to open output video file: %1 + Falha ao abrir o ficheiro de saída do vídeo: %1 + + + + Native (%0x%1) + Nativo (%0x%1) + + + + Select output file + Selecione o ficheiro de saída + + + + Record Video + Gravar Vídeo + + + + Start + Iniciar + + + + Stop + Parar + + + + Select File + Selecionar Ficheiro + + + + Presets + Pre-definições + + + + High &Quality + Qualidade &Alta + + + + &YouTube + &YouTube + + + + + WebM + WebM + + + + + MP4 + MP4 + + + + &Lossless + &Sem Perdas + + + + 4K + 4K + + + + &1080p + &1080p + + + + &720p + &720p + + + + &480p + &480p + + + + &Native + &Nativo + + + + Format + Formato + + + + MKV + MKV + + + + AVI + AVI + + + + HEVC + HEVC + + + + HEVC (NVENC) + HEVC (NVENC) + + + + VP8 + VP8 + + + + VP9 + VP9 + + + + FFV1 + FFV1 + + + + + None + Nenhum + + + + FLAC + FLAC + + + + WavPack + WavPack + + + + Opus + Opus + + + + Vorbis + Vorbis + + + + MP3 + MP3 + + + + AAC + AAC + + + + Uncompressed + Descomprimido + + + + Bitrate (kbps) + Taxa dos bits (Kbps) + + + + ABR + ABR + + + + H.264 + H.264 + + + + H.264 (NVENC) + H.264 (NVENC) + + + + VBR + VBR + + + + CRF + CRF + + + + Dimensions + Dimensões + + + + Lock aspect ratio + Travar a proporção do aspeto + + + + Show advanced + Mostrar opções avançadas + + + + QGBA::Window + + + Archives (%1) + Ficheiros Compactados (%1) + + + + + + Select ROM + Selecionar ROM + + + + Select folder + Selecionar pasta + + + + + Select save + Selecionar save + + + + Select patch + Selecionar patch + + + + Patches (*.ips *.ups *.bps) + Patches (*.ips *.ups *.bps) + + + + Select e-Reader dotcode + Selecionar dotcode do e-Reader + + + + e-Reader card (*.raw *.bin *.bmp) + Cartão do e-Reader (*.raw *.bin *.bmp) + + + + Select image + Selecionar imagem + + + + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) + Ficheiro de imagem (*.png *.gif *.jpg *.jpeg);;Todos os ficheiros (*) + + + + GameShark saves (*.sps *.xps) + Saves do GameShark (*.sps *.xps) + + + + Select video log + Selecionar registo do vídeo + + + + Video logs (*.mvl) + Registos do vídeo (*.mvl) + + + + Crash + Crash + + + + The game has crashed with the following error: + +%1 + O jogo teve um crash com o seguinte erro: + +%1 + + + + Couldn't Start + Não Pôde Iniciar + + + + Could not start game. + Não pôde iniciar o jogo. + + + + Unimplemented BIOS call + Chamada da BIOS não implementada + + + + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. + Este jogo usa uma chamada de BIOS que não está implementada. Por favor use a BIOS oficial para uma melhor experiência. + + + + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. + Falhou em criar um aparelho de exibição apropriado, voltando a exibição por software. Os jogos podem executar lentamente, especialmente com janelas maiores. + + + + Really make portable? + Realmente tornar portátil? + + + + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? + Isto fará o emulador carregar a configuração dele do mesmo diretório que o executável. Quer continuar? + + + + Restart needed + Reiniciar é necessário + + + + Some changes will not take effect until the emulator is restarted. + Algumas mudanças não terão efeito até o emulador ser reiniciado. + + + + - Player %1 of %2 + - Jogador %1 de %2 + + + + %1 - %2 + %1 - %2 + + + + %1 - %2 - %3 + %1 - %2 - %3 + + + + %1 - %2 (%3 fps) - %4 + %1 - %2 (%3 fps) - %4 + + + + &File + &Ficheiro + + + + Load &ROM... + Carregar &ROM... + + + + Load ROM in archive... + Carregar ROM no arquivo... + + + + Add folder to library... + Adicionar pasta a biblioteca... + + + + Save games (%1) + Saves dos jogos (%1) + + + + Select save game + Selecione save do jogo + + + + mGBA save state files (%1) + Ficheiro do save state do mGBA (%1) + + + + + Select save state + Selecione um save state + + + + Select e-Reader card images + Selecionar imagens do cartão do e-Reader + + + + Image file (*.png *.jpg *.jpeg) + Ficheiro da imagem (*.png *.jpg *.jpeg) + + + + Conversion finished + Conversão concluída + + + + %1 of %2 e-Reader cards converted successfully. + %1 de %2 cartões do e-Reader convertidos com sucesso. + + + + Load alternate save game... + Carregar save alternativo do jogo... + + + + Load temporary save game... + Carregar save temporário do jogo... + + + + Load &patch... + Carregar &patch... + + + + Boot BIOS + Dar Boot na BIOS + + + + Replace ROM... + Substituir a ROM... + + + + Scan e-Reader dotcodes... + Escanear dotcodes do e-Reader... + + + + Convert e-Reader card image to raw... + Converter imagem do cartão do e-Reader para natural... + + + + ROM &info... + Informações da &ROM... + + + + Recent + Recentes + + + + Make portable + Tornar portátil + + + + &Load state + &Carregar state + + + + Load state file... + Carregar ficheiro do state... + + + + &Save state + &Gravar o state + + + + Save state file... + Ficheiro do save state... + + + + Quick load + Carregamento rápido + + + + Quick save + Salvamento rápido + + + + Load recent + Carregar recentes + + + + Save recent + Gravar recentes + + + + Undo load state + Desfazer o carregamento do state + + + + Undo save state + Desfazer o save state + + + + + State &%1 + State &%1 + + + + Load camera image... + Carregar a imagem da câmara... + + + + Convert save game... + Converter o save do jogo... + + + + GameShark saves (*.gsv *.sps *.xps) + Saves do GameShark (*.gsv *.sps *.xps) + + + + Reset needed + É necessário resetar + + + + Some changes will not take effect until the game is reset. + Algumas mudanças não terão efeito até o jogo ser resetado. + + + + Save games + Saves dos jogos + + + + Import GameShark Save... + Importar Save do GameShark... + + + + Export GameShark Save... + Exportar Save do GameShark... + + + + Automatically determine + Determinar automaticamente + + + + Use player %0 save game + Usar o save do jogo %0 do jogador + + + + New multiplayer window + Nova janela multi-jogador + + + + Connect to Dolphin... + Conectar ao Dolphin... + + + + Report bug... + Reportar bug... + + + + About... + Sobre... + + + + E&xit + S&air + + + + &Emulation + &Emulação + + + + &Reset + &Resetar + + + + Sh&utdown + De&sligar + + + + Yank game pak + Arrancar o game pak + + + + &Pause + &Pausar + + + + &Next frame + &Próximo frame + + + + Fast forward (held) + Avanço rápido (segurado) + + + + &Fast forward + &Avanço rápido + + + + Fast forward speed + Velocidade do avanço rápido + + + + Unbounded + Ilimitado + + + + %0x + %0x + + + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + + Rewind (held) + Retroceder (segurado) + + + + Re&wind + Re&troceder + + + + Step backwards + Voltar um passo + + + + Solar sensor + Sensor solar + + + + Increase solar level + Aumentar nível solar + + + + Decrease solar level + Diminuir nível solar + + + + Brightest solar level + Nível solar mais brilhante + + + + Darkest solar level + Nível solar mais escuro + + + + Brightness %1 + Brilho %1 + + + + Game Boy Printer... + Impressora do Game Boy... + + + + BattleChip Gate... + Portal do BattleChip... + + + + Audio/&Video + Áudio/&Vídeo + + + + Frame size + Tamanho do frame + + + + %1× + %1× + + + + Toggle fullscreen + Alternar ecrã inteiro + + + + Lock aspect ratio + Travar a proporção do aspeto + + + + Force integer scaling + Forçar o dimensionamento do inteiro + + + + Interframe blending + Mistura do interframe + + + + Bilinear filtering + Filtragem bilinear + + + + Frame&skip + Frame&skip + + + + Mute + Mudo + + + + FPS target + FPS alvo + + + + Native (59.7275) + Nativo (59,7275) + + + + Take &screenshot + Tirar &screenshot + + + + F12 + F12 + + + + Record A/V... + Gravar A/V... + + + + Record GIF/WebP/APNG... + Gravar GIF/WebP/APNG... + + + + Video layers + Camadas do vídeo + + + + Audio channels + Canais de áudio + + + + Adjust layer placement... + Ajustar posicionamento da camada... + + + + &Tools + &Ferramentas + + + + View &logs... + Visualizar &registos... + + + + Game &overrides... + Substituições &do jogo... + + + + Game Pak sensors... + Sensores do Game Pak... + + + + &Cheats... + &Trapaças... + + + + Create forwarder... + Criar encaminhador... + + + + Settings... + Configurações... + + + + Open debugger console... + Abrir console do debugger... + + + + Start &GDB server... + Iniciar servidor do &GDB... + + + + Scripting... + Scripting... + + + + Game state views + Visualizações do estado do jogo + + + + View &palette... + Visualizar &paleta... + + + + View &sprites... + Visualizar &imagens móveis... + + + + View &tiles... + Visualizar &ladrilhos... + + + + View &map... + Visualizar &mapa... + + + + &Frame inspector... + Inspetor dos &frames... + + + + View memory... + Visualizar memória... + + + + Search memory... + Procurar na memória... + + + + View &I/O registers... + Visualizar registos de &E/S... + + + + Record debug video log... + Gravar registo do vídeo de debug... + + + + Stop debug video log + Parar o registo do vídeo de debug + + + + Exit fullscreen + Sair do ecrã inteiro + + + + GameShark Button (held) + Botão do GameShark (segurado) + + + + Autofire + Auto-disparar + + + + Autofire A + Auto-disparar A + + + + Autofire B + Auto-disparar B + + + + Autofire L + Auto-disparar L + + + + Autofire R + Auto-disparar R + + + + Autofire Start + Auto-disparar Start + + + + Autofire Select + Auto-disparar Select + + + + Autofire Up + Auto-disparar Para Cima + + + + Autofire Right + Auto-disparar Direita + + + + Autofire Down + Auto-disparar Para Baixo + + + + Autofire Left + Auto-disparar Esquerda + + + + Clear + Limpar + + + + QObject + + + %1 byte + %1 byte + + + + %1 kiB + %1 kiBs + + + + %1 MiB + %1 MiBs + + + + GBA + GBA + + + + GB + GBs + + + + ? + ? + + + + Super (L) + Super (E) + + + + Super (R) + Super (D) + + + + Menu + Menu + + + + QShortcut + + + Shift + Shift + + + + Control + Control + + + + Alt + Alt + + + + Meta + Meta + + + diff --git a/src/platform/qt/ts/mgba-pt_BR.ts b/src/platform/qt/ts/mgba-pt_BR.ts index d54c32360..2cbfde528 100644 --- a/src/platform/qt/ts/mgba-pt_BR.ts +++ b/src/platform/qt/ts/mgba-pt_BR.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + ROMs do Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + ROMs do Game Boy (%1) + + + + All ROMs (%1) + Todas as ROMs (%1) + + + + %1 Video Logs (*.mvl) + %1 Registros do Vídeo (*.mvl) + + QGBA::AboutScreen @@ -33,7 +56,7 @@ O Game Boy Advance é uma marca registrada da Nintendo Co., Ltd. {projectName} is an open-source Game Boy Advance emulator - O {projectName} é um emulador de Game Boy Advance de código fonte aberto + O {projectName} é um emulador de Game Boy Advance de código-fonte aberto @@ -92,22 +115,22 @@ Tamanho do download: %3 QGBA::ApplicationUpdater - + Stable Estável - + Development Desenvolvimento - + Unknown Desconhecido - + (None) (Nenhum) @@ -259,12 +282,12 @@ Tamanho do download: %3 Show advanced - Mostrar opções avançadas + Mostrar as opções avançadas BattleChip data missing - Portal do BattleChip + Dados do BattleChip ausentes @@ -364,48 +387,48 @@ Tamanho do download: %3 QGBA::CoreController - + Reset r%1-%2 %3 Resetar r%1-%2 %3 - - + + Rewinding not currently enabled O rebobinamento não está ativado atualmente - + Reset the game? Resetar o jogo? - + Most games will require a reset to load the new save. Do you want to reset now? A maioria dos jogos requerirão um reset pra carregar o novo save. Você quer resetar agora? - + Failed to open save file: %1 Falhou em abrir o arquivo do save: %1 - + Failed to open game file: %1 Falhou em abrir o arquivo do jogo: %1 - + Can't yank pack in unexpected platform! Não pode arrancar o pacote numa plataforma inesperada! - + Failed to open snapshot file for reading: %1 Falhou em abrir o arquivo do snapshot pra leitura: %1 - + Failed to open snapshot file for writing: %1 Falhou em abrir o arquivo do snapshot pra gravação: %1 @@ -413,19 +436,19 @@ Tamanho do download: %3 QGBA::CoreManager - + Failed to open game file: %1 Falhou em abrir o arquivo do jogo: %1 - + Could not load game. Are you sure it's in the correct format? Não pôde carregar o jogo. Você tem certeza que está no formato correto? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). - Falhou em abrir o abrir o arquivo de salvamento; Os salvamentos dentro do jogo não podem ser atualizados. Por favor tenha certeza que o diretório de salvamento seja gravável sem privilégios adicionais (ex: UAC no Windows). + Falhou em abrir o abrir o arquivo de save; Os saves dentro do jogo não podem ser atualizados. Por favor tenha certeza que o diretório de save seja gravável sem privilégios adicionais (ex: UAC no Windows). @@ -449,7 +472,7 @@ Tamanho do download: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing Não pôde abrir o histórico do CLI pra gravar @@ -502,6 +525,200 @@ Tamanho do download: %3 Não pôde conectar com o Dolphin. + + QGBA::ForwarderGenerator + + + 3DS + 3DS + + + + Vita + Vita + + + + QGBA::ForwarderGenerator3DS + + + Icon + Ícone + + + + Banner + Banner + + + + QGBA::ForwarderGeneratorVita + + + Bubble + Bolha + + + + Background + 2º plano + + + + Startup + Inicialização + + + + QGBA::ForwarderView + + + Create forwarder + Criar encaminhador + + + + Files + Arquivos + + + + ROM file: + Arquivo da ROM: + + + + + + Browse + Explorar + + + + Output filename: + Nome do arquivo de saída: + + + + Forwarder base: + Base do encaminhador: + + + + Latest stable version + Última versão estável + + + + Latest development build + Último build de desenvolvimento + + + + Specific file + Arquivo específico + + + + Base file: + Arquivo base: + + + + System + Sistema + + + + 3DS + 3DS + + + + Vita + Vita + + + + Presentation + Apresentação + + + + Title: + Título: + + + + Images: + Imagens: + + + + Use default image + Usar imagem padrão + + + + Preferred size: + Tamanho preferido: + + + + Select image file + Selecionar arquivo de imagem + + + + Select ROM file + Selecione o arquivo da ROM + + + + Select output filename + Selecionar o nome do arquivo de saída + + + + Select base file + Selecionar o arquivo base + + + + Build finished + Compilação concluída + + + + Forwarder finished building + O encaminhador encerrou a compilação + + + + Build failed + Falhou em criar o build + + + + Failed to build forwarder + Falhou em criar o encaminhador + + + + %1 installable package (*.%2) + %1 pacote instalável (*.%2) + + + + Select an image + Selecione uma imagem + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Tamanho do download: %3 Resetar - + Export frame Exportar frame - + Portable Network Graphics (*.png) Gráficos Portáteis da Rede (*.png) - + None Nenhum - + Background 2º plano - + Window Janela - + Objwin Objwin - + Sprite Imagem Móvel - + Backdrop 2º Plano - + Frame Frame - + %1 %2 %1 %2 @@ -593,30 +810,30 @@ Tamanho do download: %3 QGBA::GBAApp - + Enable Discord Rich Presence - Ativar o Discord Rich Presence + Ativar a Presença Rica no Discord QGBA::GBAKeyEditor - + Clear Button Limpar Botão - + Clear Analog Limpar Analógico - + Refresh Atualizar - + Set all Definir todos @@ -729,7 +946,7 @@ Tamanho do download: %3 Frameskip - Pulo dos Frames + Frameskip @@ -750,148 +967,168 @@ Tamanho do download: %3 QGBA::GameBoy - - + + Autodetect Auto-detectar - + Game Boy (DMG) Game Boy (DMG) - + Game Boy Pocket (MGB) Game Boy Pocket (MGB) - + Super Game Boy (SGB) Super Game Boy (SGB) - + Super Game Boy 2 (SGB) Super Game Boy 2 (SGB) - + Game Boy Color (CGB) Game Boy Color (CGB) - + Game Boy Advance (AGB) Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) Super Game Boy Color (SGB + CGB) - + ROM Only So a ROM - + MBC1 MBC1 - + MBC2 MBC2 - + MBC3 MBC3 - + MBC3 + RTC MBC3 + RTC - + MBC5 MBC5 - + MBC5 + Rumble MBC5 + Rumble - + MBC6 MBC6 - + MBC7 (Tilt) MBC7 (Inclinação) - + MMM01 MMM01 - + HuC-1 HuC-1 - + HuC-3 HuC-3 - + Pocket Cam Câmara de Bolso - + TAMA5 TAMA5 - + Wisdom Tree Árvore da Sabedoria - + + NT (old 1) + NT (antigo 1) + + + + NT (old 2) + NT (antigo 2) + + + NT (new) NT (novo) - + Pokémon Jade/Diamond Pokémon Jade/Diamond - + BBD BBD - + Hitek Hitek - + + GGB-81 + GGB-81 + + + + Li Cheng + Li Cheng + + + Sachen (MMC1) Sachen (MMC1) - + Sachen (MMC2) Sachen (MMC2) @@ -923,17 +1160,17 @@ Tamanho do download: %3 Mode 0: 4 tile layers - Modo 0: 4 camadas de ladrilhos + Modo 0: 4 camadas de mosaicos Mode 1: 2 tile layers + 1 rotated/scaled tile layer - Modo 1: 2 camadas de ladrilhos + 1 camada de ladrilhos rotacionada/redimensionada + Modo 1: 2 camadas de mosaicos + 1 camada de mosaico rotacionada/redimensionada Mode 2: 2 rotated/scaled tile layers - Modo 2: 2 camadas de ladrilhos rotacionadas/redimensionadas + Modo 2: 2 camadas de mosaicos rotacionadas/redimensionadas @@ -968,7 +1205,7 @@ Tamanho do download: %3 Linear OBJ tile mapping - Mapeamento do ladrilho do OBJ linear + Mapeamento do mosaico do OBJ linear @@ -1074,7 +1311,7 @@ Tamanho do download: %3 Tile data base (* 16kB) - Banco de dados dos ladrilhos (* 16 kBs) + Banco de dados dos mosaicos (* 16 kBs) @@ -1098,7 +1335,7 @@ Tamanho do download: %3 Tile map base (* 2kB) - Base do mapa dos ladrilhos (* 2 kBs) + Base do mapa dos mosaicos (* 2 kBs) @@ -2543,7 +2780,7 @@ Tamanho do download: %3 Background tile map - Mapa dos ladrilhos do 2º plano + Mapa dos mosaicos do 2º plano @@ -2560,7 +2797,7 @@ Tamanho do download: %3 Background tile data - Dados dos ladrilhos do 2º plano + Dados dos mosaicos do 2º plano @@ -2580,7 +2817,7 @@ Tamanho do download: %3 Window tile map - Mapa dos ladrilhos da janela + Mapa dos mosaicos da janela @@ -2769,26 +3006,11 @@ Tamanho do download: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super (E) - - - - Super (R) - Super (D) - - - - Menu - Menu - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Tamanho do download: %3 Corrompido - + Slot %1 Slot %1 @@ -3107,7 +3329,7 @@ Tamanho do download: %3 Tile base - Base dos ladrilhos + Base dos mosaicos @@ -3136,39 +3358,39 @@ Tamanho do download: %3 Espelho - + None Nenhum - + Both Ambos - + Horizontal Horizontal - + Vertical Vertical - - - + + + N/A N/D - + Export map Exportar mapa - + Portable Network Graphics (*.png) Gráficos Portáteis da Rede (*.png) @@ -3419,22 +3641,22 @@ Tamanho do download: %3 Atualizar - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 byte%2 @@ -3525,6 +3747,24 @@ Tamanho do download: %3 Frame %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -3631,7 +3871,7 @@ Tamanho do download: %3 Tile - Ladrilho + Mosaico @@ -4023,6 +4263,7 @@ Tamanho do download: %3 + (unknown) (desconhecido) @@ -4066,6 +4307,11 @@ Tamanho do download: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4087,7 +4333,7 @@ Tamanho do download: %3 <html><head/><body><p>To file a bug report, please first generate a report file to attach to the bug report you're about to file. It is recommended that you include the save files, as these often help with debugging issues. This will collect some information about the version of {projectName} you're running, your configuration, your computer, and the game you currently have open (if any). Once this collection is completed you can review all of the information gathered below and save it to a zip file. The collection will automatically attempt to redact any personal information, such as your username if it's in any of the paths gathered, but just in case you can edit it afterwards. After you have generated and saved it, please click the button below or go to <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> to file the bug report on GitHub. Make sure to attach the report you generated!</p></body></html> - <html><head/><body><p>Pra apresentar um relatório de bug por favor gere primeiro um arquivo de relatório pra anexar ao relatório do bug que você está pra apresentar. É recomendado que você inclua os arquivos dos saves como estes frequentemente ajudam com problemas de debugging. Isto coletará um pouco de informação sobre a versão do {projectName} que você está em executando, suas configurações, seu computador e o jogo que você abriu atualmente (se algum). Uma vez que esta coleção estiver completada você pode rever toda a informação coletada abaixo e salvá-la num arquivo zip. A coleção tentará automaticamente reescrever qualquer informação pessoal, tal como seu nome de usuário se está em quaisquer dos caminhos coletados, mas no caso você pode editá-lo mais tarde. Depois que você o gerou e o salvou, por favor clique no botão abaixo ou vá em <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> pra apresentar o relatório do bug no GitHub. Tenha a certeza de anexar o relatório que você gerou!</p></body></html> + <html><head/><body><p>Pra apresentar um relatório de bug por favor gere primeiro um arquivo de relatório pra anexar ao relatório do bug que você está pra apresentar. É recomendado que você inclua os arquivos dos saves como estes frequentemente ajudam com problemas de debugging. Isto coletará um pouco de informação sobre a versão do {projectName} que você está em executando, suas configurações, seu computador e o jogo que você abriu atualmente (se houver algum). Uma vez que esta coleção estiver completada você pode rever toda a informação coletada abaixo e salvá-la num arquivo zip. A coleção tentará automaticamente reescrever qualquer informação pessoal tal como seu nome de usuário se ele estiver em quaisquer dos caminhos coletados mas dependendo do caso você pode editá-lo mais tarde. Depois que você o gerou e o salvou por favor clique no botão abaixo ou vá em <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> pra apresentar o relatório do bug no GitHub. Tenha a certeza de anexar o relatório que você gerou!</p></body></html> @@ -4112,7 +4358,7 @@ Tamanho do download: %3 Create and include savestate - Criar e incluir savestate + Criar e incluir o save state @@ -4173,7 +4419,7 @@ Tamanho do download: %3 Não foram encontradas conversões válidas - + Cannot convert save games between platforms Não pôde converter os saves do jogo entre as plataformas @@ -4199,92 +4445,97 @@ Tamanho do download: %3 Arquivo de saída - + %1 %2 save game %1 %2 save do jogo - + little endian little endian - + big endian big endian - + SRAM SRAM - + %1 flash %1 flash - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 - empacotou o MBC2 + Empacotou o MBC2 - + unpacked MBC2 - desempacotou o MBC2 + Desempacotou o MBC2 - + MBC6 flash Flash do MBC6 - + MBC6 combined SRAM + flash MBC6 SRAM combinado + flash - + MBC6 SRAM SRAM do MBC6 - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game - %1 save state com %2 saves dos jogos embutidos + %1 save state com %2 saves do jogo embutido - + %1 SharkPort %2 save game %1 SharkPort %2 save do jogo - + %1 GameShark Advance SP %2 save game %1 GameShark Advance SP %2 save do jogo @@ -4292,7 +4543,7 @@ Tamanho do download: %3 QGBA::ScriptingTextBuffer - + Untitled buffer Buffer sem título @@ -4337,7 +4588,7 @@ Tamanho do download: %3 Select script to load - Selecionar o script a carregar + Selecione o script a carregar @@ -4395,7 +4646,7 @@ Tamanho do download: %3 MM/dd/yy hh:mm:ss AP - MM/dd/yy hh:mm:ss AP + MM/dd/aa hh:mm:ss AP @@ -4438,95 +4689,105 @@ Tamanho do download: %3 QGBA::SettingsView - - + + Qt Multimedia Multimídia do Qt - + SDL SDL - + Software (Qt) Software (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (forçar a versão 1.x) - + None Nenhum - + None (Still Image) Nenhum (Imagem Parada) - + Keyboard Teclado - + Controllers Controles - + Shortcuts Atalhos - - + + Shaders Shaders - + Select BIOS Selecionar BIOS - + Select directory Selecione o diretório - + + Select image + Selecionar imagem + + + + Image file (*.png *.jpg *.jpeg) + Arquivo da imagem (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never Nunca - + Just now Aconteceu agora - + Less than an hour ago Menos do que uma hora atrás - + %n hour(s) ago %n hora atrás @@ -4534,7 +4795,7 @@ Tamanho do download: %3 - + %n day(s) ago %n dia atrás @@ -4645,7 +4906,7 @@ Tamanho do download: %3 samples - amostras + Amostras @@ -4733,7 +4994,7 @@ Tamanho do download: %3 - + frames frames @@ -4745,7 +5006,7 @@ Tamanho do download: %3 frames per second - frames por segundo + Frames por segundo @@ -4783,7 +5044,7 @@ Tamanho do download: %3 Pause - Pausa + Pausar @@ -4823,80 +5084,90 @@ Tamanho do download: %3 Show emulation info on reset - Mostrar informações da emulação no reset + Mostrar informações da emulação ao resetar - + + Custom border: + + + + Current channel: Canal atual: - + Current version: Versão atual: - + Update channel: Canal da atualização: - + Available version: Versão disponível: - + (Unknown) (Desconhecido) - + Last checked: Verificado pela última vez: - + Automatically check on start Verificar automaticamente ao iniciar - + Check now Verificar agora - + + Rewind speed: + + + + Default color palette only Só a cor padrão da paleta - + SGB color palette if available Paleta das cores do SGB se disponível - + GBC color palette if available Paleta das cores do GBC se disponível - + SGB (preferred) or GBC color palette if available SGB (preferido) ou paleta das cores do GBC se disponível - + Game Boy Camera Câmera do Game Boy - + Driver: Driver: - + Source: Fonte: @@ -4937,12 +5208,12 @@ Tamanho do download: %3 Carregar dados extras do state: - + Enable VBA bug compatibility in ROM hacks Ativar compatibilidade dos bugs do VBA nos hacks das ROMs - + Preset: Pré-definições: @@ -4952,34 +5223,34 @@ Tamanho do download: %3 Mostrar o nome do arquivo ao invés do nome da ROM na barra de título - + Fast forward (held) speed: - Velocidade do avanço rápido (segurado): + Velocidade do avanço rápido (pressionado): - + (240×160) (240×160) - + Log to file Registrar no arquivo - + Log to console Registrar no console - + Select Log File - Selecionar Arquivo de Registro + Selecionar Arquivo do Registro Force integer scaling - Forçar dimensionamento do inteiro + Forçar o dimensionamento do inteiro @@ -5024,51 +5295,51 @@ Tamanho do download: %3 Show FPS in title bar - Mostrar FPS na barra de título + Mostrar o FPS na barra do título Enable Discord Rich Presence - Ativar o Discord Rich Presence + Ativar a Presença Rica do Discord - + Fast forward speed: Velocidade do avanço rápido: - - + + Unbounded Ilimitado - + Enable rewind Ativar retrocesso - + Rewind history: Histórico do retrocesso: - + Idle loops: Repetições inativas: - + Run all Executar todos - + Remove known Remover conhecidos - + Detect and remove Detectar e remover @@ -5085,85 +5356,86 @@ Tamanho do download: %3 Códigos de trapaça - + Preload entire ROM into memory Pré-carregar a ROM inteira na memória - + Autofire interval: Intervalo do auto-disparo: - + Enable Game Boy Player features by default Ativar funções do Game Boy Player por padrão - + Video renderer: Renderizador do vídeo: - + Software Software - + OpenGL enhancements Melhorias do OpenGL - + High-resolution scale: - Escala da alta-resolução: + Escala de alta-resolução: - + XQ GBA audio (experimental) Áudio do XQ GBA (experimental) - + GB BIOS file: Arquivo da BIOS do GB: - - - - - - - - - + + + + + + + + + + Browse Explorar - + Use BIOS file if found Usar o arquivo da BIOS se encontrado - + Skip BIOS intro Ignorar a introdução da BIOS - + GBA BIOS file: Arquivo da BIOS do GBA: - + GBC BIOS file: Arquivo da BIOS do GBC: - + SGB BIOS file: Arquivo da BIOS do SGB: @@ -5173,91 +5445,91 @@ Tamanho do download: %3 Auto-salvar o state periodicamente - + Save games Saves dos jogos - - - - - + + + + + Same directory as the ROM O mesmo diretório que a ROM - + Save states Save states - + Screenshots Screenshots - + Patches Patches - + Cheats Trapaças - + Models Modelos - + GB only: - Só no GB: + Só pro GB: - + SGB compatible: Compatível com o SGB: - + GBC only: - Só no GBC: + Só pro GBC: - + GBC compatible: Compatível com o GBC: - + SGB and GBC compatible: Compatível com o SGB e o GBC: - + Game Boy palette Paleta do Game Boy - + Default BG colors: - Cores padrão do BG: + Cores padrão do 2º plano: - + Super Game Boy borders Bordas do Super Game Boy - + Default sprite colors 1: Cores padrão da imagem móvel 1: - + Default sprite colors 2: Cores padrão da imagem móvel 2: @@ -5270,27 +5542,28 @@ Tamanho do download: %3 Nenhum shader ativo - + + Load shader Carregar shader - + No shader loaded Nenhum shader carregado - + by %1 por %1 - + Preprocessing Pré-processamento - + Pass %1 Passe %1 @@ -5333,17 +5606,17 @@ Tamanho do download: %3 QGBA::ShortcutModel - + Action Ação - + Keyboard Teclado - + Gamepad Controle @@ -5376,7 +5649,7 @@ Tamanho do download: %3 Export tiles - Exportar ladrilhos + Exportar mosaicos @@ -5387,12 +5660,12 @@ Tamanho do download: %3 Export tile - Exportar ladrilho + Exportar mosaico Tiles - Ladrilhos + Mosaicos @@ -5422,7 +5695,7 @@ Tamanho do download: %3 Tiles per row - Ladrilhos por linha + Mosaicos por linha @@ -5452,7 +5725,7 @@ Tamanho do download: %3 Copy Selected - Copiar Selecionado + Copiar o Selecionado @@ -5463,17 +5736,17 @@ Tamanho do download: %3 QGBA::VideoView - + Failed to open output video file: %1 Falhou em abrir o arquivo de saída do vídeo: %1 - + Native (%0x%1) Nativo (%0x%1) - + Select output file Selecione o arquivo de saída @@ -5608,7 +5881,7 @@ Tamanho do download: %3 WavPack - + WavPack @@ -5638,7 +5911,7 @@ Tamanho do download: %3 Bitrate (kbps) - Taxa dos bits (kbps) + Taxa dos bits (Kbps) @@ -5678,106 +5951,86 @@ Tamanho do download: %3 Show advanced - Mostrar as opções avançadas + Mostrar opções avançadas QGBA::Window - - Game Boy Advance ROMs (%1) - ROMs do Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - ROMs do Game Boy (%1) - - - - All ROMs (%1) - Todas as ROMs (%1) - - - - %1 Video Logs (*.mvl) - %1 Registros do Vídeo (*.mvl) - - - + Archives (%1) Arquivos Compactados (%1) - - - + + + Select ROM Selecionar ROM - + Select folder Selecionar pasta - - + + Select save Selecionar save - + Select patch Selecionar patch - + Patches (*.ips *.ups *.bps) Patches (*.ips *.ups *.bps) - + Select e-Reader dotcode Selecionar dotcode do e-Reader - + e-Reader card (*.raw *.bin *.bmp) Cartão do e-Reader (*.raw *.bin *.bmp) - + Select image Selecionar imagem - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Arquivo de imagem (*.png *.gif *.jpg *.jpeg);;Todos os arquivos (*) - + GameShark saves (*.sps *.xps) Saves do GameShark (*.sps *.xps) - + Select video log Selecionar registro do vídeo - + Video logs (*.mvl) Registros do vídeo (*.mvl) - + Crash Crash - + The game has crashed with the following error: %1 @@ -5786,684 +6039,699 @@ Tamanho do download: %3 %1 - + Unimplemented BIOS call Chamada da BIOS não implementada - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Este jogo usa uma chamada de BIOS que não está implementada. Por favor use a BIOS oficial pra uma melhor experiência. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Falhou em criar um dispositivo de exibição apropriado, voltando a exibição por software. Os jogos podem executar lentamente, especialmente com janelas maiores. - + Really make portable? Realmente tornar portátil? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? Isto fará o emulador carregar sua configuração do mesmo diretório que o executável. Você quer continuar? - + Restart needed Reiniciar é necessário - + Some changes will not take effect until the emulator is restarted. Algumas mudanças não terão efeito até o emulador ser reiniciado. - + - Player %1 of %2 - Jogador %1 de %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 %1 - %2 (%3 fps) - %4 - + &File &Arquivo - + Load &ROM... Carregar &ROM... - + Load ROM in archive... Carregar ROM no arquivo compactado... - + Add folder to library... Adicionar pasta a biblioteca... - + Save games Saves dos jogos - + Automatically determine Determinar automaticamente - + Use player %0 save game Usar o save do jogo %0 do jogador - + Load &patch... Carregar &patch... - + Boot BIOS Dar Boot na BIOS - + Replace ROM... Substituir a ROM... - + ROM &info... Informações da &ROM... - + Recent Recentes - + Make portable Tornar portátil - + &Load state &Carregar state - + Report bug... Reportar bug... - + About... Sobre... - + Game Pak sensors... Sensores do Game Pak... - + Clear Limpar - + Load state file... Carregar arquivo do state... - + Save games (%1) Saves dos jogos (%1) - + Select save game Selecione save do jogo - + mGBA save state files (%1) Arquivos do save state do mGBA (%1) - - + + Select save state Selecione um save state - + Select e-Reader card images Selecionar imagens do cartão do e-Reader - + Image file (*.png *.jpg *.jpeg) Arquivo da imagem (*.png *.jpg *.jpeg) - + Conversion finished Conversão concluída - + %1 of %2 e-Reader cards converted successfully. %1 de %2 cartões do e-Reader convertidos com sucesso. - + Load alternate save game... Carregar save alternativo do jogo... - + Load temporary save game... Carregar save temporário do jogo... - + Convert e-Reader card image to raw... Converter imagem do cartão do e-Reader pro natural... - + &Save state &Salvar o state - + Save state file... Arquivo do save state... - + Quick load Carregamento rápido - + Quick save Salvamento rápido - + Load recent Carregar recentes - + Save recent Salvar recentes - + Undo load state Desfazer o carregamento do state - + Undo save state - Desfazer o salvamento do state + Desfazer o save state - - + + State &%1 State &%1 - + Load camera image... Carregar a imagem da câmera... - + Convert save game... Converter o save do jogo... - + GameShark saves (*.gsv *.sps *.xps) Saves do GameShark (*.gsv *.sps *.xps) - + Reset needed É necessário resetar - + Some changes will not take effect until the game is reset. Algumas mudanças não terão efeito até o jogo ser resetado. - + New multiplayer window Nova janela multi-jogador - + Connect to Dolphin... Conectar ao Dolphin... - + E&xit S&air - + &Emulation &Emulação - + &Reset &Resetar - + Sh&utdown De&sligar - + Yank game pak Arrancar o game pak - + &Pause &Pausar - + &Next frame &Próximo frame - + Fast forward (held) Avanço rápido (segurado) - + &Fast forward &Avanço rápido - + Fast forward speed Velocidade do avanço rápido - + Unbounded Ilimitado - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Retroceder (segurado) - + Re&wind Re&troceder - + Step backwards Voltar um passo - + Solar sensor Sensor solar - + Increase solar level Aumentar nível solar - + Decrease solar level Diminuir nível solar - + Brightest solar level Nível solar mais brilhante - + Darkest solar level Nível solar mais escuro - + Brightness %1 Brilho %1 - + Audio/&Video Áudio/&Vídeo - + Frame size Tamanho do frame - + Toggle fullscreen Alternar tela cheia - + Lock aspect ratio Travar a proporção do aspecto - + Force integer scaling Forçar o dimensionamento do inteiro - + Bilinear filtering Filtragem bilinear - + Frame&skip Frame&skip - + Mute Mudo - + FPS target FPS alvo - + Native (59.7275) Nativo (59,7275) - + Take &screenshot Tirar &screenshot - + F12 F12 - + Game Boy Printer... Impressora do Game Boy... - + BattleChip Gate... Portal do BattleChip... - + %1× %1× - + Interframe blending Mistura do interframe - + Record A/V... Gravar A/V... - + Video layers Camadas do vídeo - + Audio channels Canais de áudio - + Adjust layer placement... Ajustar posicionamento da camada... - + &Tools &Ferramentas - + View &logs... Visualizar &registros... - + Game &overrides... Substituições &do jogo... - + Couldn't Start Não Pôde Iniciar - + Could not start game. Não pôde iniciar o jogo. - + Scan e-Reader dotcodes... Escanear dotcodes do e-Reader... - + Import GameShark Save... Importar Save do GameShark... - + Export GameShark Save... Exportar Save do GameShark... - + Record GIF/WebP/APNG... Gravar GIF/WebP/APNG... - + &Cheats... &Trapaças... - + Settings... Configurações... - + Open debugger console... Abrir console do debugger... - + Start &GDB server... Iniciar servidor do &GDB... - + Scripting... Scripting... - + + Create forwarder... + Criar encaminhador... + + + Game state views Visualizações do estado do jogo - + View &palette... Visualizar &paleta... - + View &sprites... Visualizar &imagens móveis... - + View &tiles... - Visualizar &ladrilhos... + Visualizar &mosaicos... - + View &map... Visualizar &mapa... - + &Frame inspector... Inspetor dos &frames... - + View memory... Visualizar memória... - + Search memory... Procurar na memória... - + View &I/O registers... Visualizar registros de &E/S... - + Record debug video log... Gravar registro do vídeo de debug... - + Stop debug video log Parar o registro do vídeo de debug - + Exit fullscreen Sair da tela cheia - + GameShark Button (held) Botão do GameShark (segurado) - + Autofire Auto-disparar - + Autofire A Auto-disparar A - + Autofire B Auto-disparar B - + Autofire L Auto-disparar L - + Autofire R Auto-disparar R - + Autofire Start Auto-disparar Start - + Autofire Select Auto-disparar Select - + Autofire Up Auto-disparar Pra Cima - + Autofire Right Auto-disparar Direita - + Autofire Down Auto-disparar Pra Baixo - + Autofire Left Auto-disparar Esquerda @@ -6471,55 +6739,70 @@ Tamanho do download: %3 QObject - + %1 byte %1 byte - + %1 kiB %1 kiBs - + %1 MiB %1 MiBs - + GBA GBA - + GB GBs - + ? ? + + + Super (L) + Super (E) + + + + Super (R) + Super (D) + + + + Menu + Menu + QShortcut - + Shift Shift - + Control Control - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/ts/mgba-ru.ts b/src/platform/qt/ts/mgba-ru.ts index 33874b707..17147a467 100644 --- a/src/platform/qt/ts/mgba-ru.ts +++ b/src/platform/qt/ts/mgba-ru.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + Игры Game Boy Advance (%1) + + + + Game Boy ROMs (%1) + Игры Game Boy (%1) + + + + All ROMs (%1) + Все игры (%1) + + + + %1 Video Logs (*.mvl) + Журналы видео %1 (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable Стабильная - + Development В разработке - + Unknown Неизвестно - + (None) (Нет) @@ -364,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 Сброс r%1-%2 %3 - - + + Rewinding not currently enabled Обратная перемотка выключена - + Reset the game? Перезагрузить игру? - + Most games will require a reset to load the new save. Do you want to reset now? Большинству игр нужна перезагрузка, чтобы загрузить новое сохранение. Перезагрузить сейчас? - + Failed to open save file: %1 Не удалось открыть файл сохранения: %1 - + Failed to open game file: %1 Не удалось открыть файл игры: %1 - + Can't yank pack in unexpected platform! Невозможно пнуть картридж на неожиданной платформе! - + Failed to open snapshot file for reading: %1 Не удалось открыть файл изображения для считывания: %1 - + Failed to open snapshot file for writing: %1 Не удалось открыть файл изображения для записи: %1 @@ -413,17 +436,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 Не удалось открыть файл игры: %1 - + Could not load game. Are you sure it's in the correct format? Не удалось загрузить игру. Вы уверены, что она в правильном формате? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). Не удалось открыть файл с сохранениями; внутриигровые сохранения не могут быть обновлены. Убедитесь, что директория с сохранениями доступна на запись без повышения привилегий (например, UAC на Windows). @@ -449,7 +472,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing Не удалось открыть историю CLI на запись @@ -502,6 +525,200 @@ Download size: %3 Не удалось соединиться с Dolphin. + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + Фон + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + Открыть + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Download size: %3 Сброс - + Export frame Экспорт кадра - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Нет - + Background Фон - + Window Окно - + Objwin Objwin - + Sprite Спрайт - + Backdrop Подложка - + Frame Кадр - + %1 %2 %1 %2 @@ -593,7 +810,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence Вкл. расширенный статус в Discord @@ -601,22 +818,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button Сброс кнопки - + Clear Analog Сброс аналога - + Refresh Обновить - + Set all Назначить все @@ -651,7 +868,7 @@ Download size: %3 Internal change detection - + Обнаружение внутренних изменений @@ -749,149 +966,169 @@ Download size: %3 QGBA::GameBoy - - - - Autodetect - Автоопределение - - - - Game Boy (DMG) - - - - - Game Boy Pocket (MGB) - - - - - Super Game Boy (SGB) - - - - - Super Game Boy 2 (SGB) - - - Game Boy Color (CGB) - + + Autodetect + Автоопределение - Game Boy Advance (AGB) - + Game Boy (DMG) + Game Boy (DMG) - Super Game Boy Color (SGB + CGB) - + Game Boy Pocket (MGB) + Game Boy Pocket (MGB) - + + Super Game Boy (SGB) + Super Game Boy (SGB) + + + + Super Game Boy 2 (SGB) + Super Game Boy 2 (SGB) + + + + Game Boy Color (CGB) + Game Boy Color (CGB) + + + + Game Boy Advance (AGB) + Game Boy Advance (AGB) + + + + Super Game Boy Color (SGB + CGB) + Super Game Boy Color (SGB + CGB) + + + ROM Only Только ROM - - - MBC1 - - - - - MBC2 - - - - - MBC3 - - - - - MBC3 + RTC - - - - - MBC5 - - - MBC5 + Rumble - + MBC1 + MBC1 - MBC6 - + MBC2 + MBC2 - MBC7 (Tilt) - + MBC3 + MBC3 - MMM01 - + MBC3 + RTC + MBC3 + RTC - HuC-1 - + MBC5 + MBC5 - HuC-3 - + MBC5 + Rumble + MBC5 + Rumble + MBC6 + MBC6 + + + + MBC7 (Tilt) + MBC7 (Tilt) + + + + MMM01 + MMM01 + + + + HuC-1 + HuC-1 + + + + HuC-3 + HuC-3 + + + Pocket Cam - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2125,7 +2362,7 @@ Download size: %3 Value - Значение + Значение @@ -2142,7 +2379,7 @@ Download size: %3 1/64 - 1/64 + 1/64 @@ -2151,7 +2388,7 @@ Download size: %3 1/256 - 1/256 + 1/256 @@ -2160,7 +2397,7 @@ Download size: %3 1/1024 - 1/1024 + 1/1024 @@ -2479,7 +2716,7 @@ Download size: %3 1/16 - 1/16 + 1/16 @@ -2590,7 +2827,7 @@ Download size: %3 Mode - Режим + Режим @@ -2769,25 +3006,10 @@ Download size: %3 QGBA::KeyEditor - - + + --- - - - - - Super (L) - - - - - Super (R) - - - - - Menu - Меню + --- @@ -2910,7 +3132,7 @@ Download size: %3 Повреждено - + Slot %1 Слот %1 @@ -2926,12 +3148,12 @@ Download size: %3 Fatal - Фатальная ошибка + Фатальная ошибка Error - Ошибка + Ошибка @@ -2956,7 +3178,7 @@ Download size: %3 Game Error - Ошибка игры + Ошибка игры @@ -3123,7 +3345,7 @@ Download size: %3 Xform - + Xform @@ -3136,39 +3358,39 @@ Download size: %3 Зеркально - + None Нет - + Both Оба - + Horizontal Горизонтально - + Vertical Вертикально - - - + + + N/A Н/Д - + Export map Экспорт карты - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) @@ -3419,22 +3641,22 @@ Download size: %3 Обновить - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 @@ -3525,6 +3747,24 @@ Download size: %3 Кадр %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -3657,7 +3897,7 @@ Download size: %3 0x%0 - + 0x%0 @@ -3669,7 +3909,7 @@ Download size: %3 --- - + --- @@ -3679,7 +3919,7 @@ Download size: %3 OBJWIN - + OBJWIN @@ -3919,12 +4159,12 @@ Download size: %3 #%0 - + #%0 0x%0 - + 0x%0 @@ -3932,7 +4172,7 @@ Download size: %3 0x%0 (%1) - 0x%0 (%1) + 0x%0 (%1) @@ -4023,6 +4263,7 @@ Download size: %3 + (unknown) (неизвестно) @@ -4064,7 +4305,12 @@ Download size: %3 CRC32: - CRC32: + CRC32: + + + + Save file: + @@ -4097,7 +4343,7 @@ Download size: %3 Save - Сохранить + Сохранить @@ -4173,7 +4419,7 @@ Download size: %3 Совместимые конверсии не найдены - + Cannot convert save games between platforms Нельзя сконвертировать сохранения для разных платформ @@ -4199,92 +4445,97 @@ Download size: %3 Выходной файл - + %1 %2 save game - + little endian - + big endian - + SRAM - SRAM + SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4292,7 +4543,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4332,7 +4583,7 @@ Download size: %3 0 - 0 + 0 @@ -4437,96 +4688,106 @@ Download size: %3 QGBA::SettingsView - - - - Qt Multimedia - - - SDL - + + Qt Multimedia + Qt Multimedia - + + SDL + SDL + + + Software (Qt) Программный рендеринг (Qt) - - + + OpenGL - + OpenGL - + OpenGL (force version 1.x) - + None Нет - + None (Still Image) Нет (статичное изображение) - + Keyboard Клавиатура - + Controllers Контроллеры - + Shortcuts Сочетания клавиш - - + + Shaders Шейдеры - + Select BIOS Выбор BIOS - + Select directory Выбор папки - - (%1×%2) - + + Select image + Выбор изображения - + + Image file (*.png *.jpg *.jpeg) + Файл изображения (*.png *.jpg *.jpeg) + + + + (%1×%2) + (%1×%2) + + + Never Никогда - + Just now Только сейчас - + Less than an hour ago Менее часа назад - + %n hour(s) ago %n час назад @@ -4535,7 +4796,7 @@ Download size: %3 - + %n day(s) ago %n день назад @@ -4596,7 +4857,7 @@ Download size: %3 Game Boy - Game Boy + Game Boy @@ -4735,7 +4996,7 @@ Download size: %3 - + frames кадров @@ -4833,112 +5094,122 @@ Download size: %3 Показать инфо об эмуляции при перезагрузке - + + Custom border: + + + + Current channel: Текущий канал: - + Current version: Текущая версия: - + Update channel: Канал обновлений: - + Available version: Доступная версия: - + (Unknown) (Неизвестно) - + Last checked: Последняя проверка: - + Automatically check on start Проверять при запуске - + Check now Проверить - + + Rewind speed: + + + + Models Модели - + GB only: Только GB: - + SGB compatible: Совместимость с SGB: - + GBC only: Только GBC: - + GBC compatible: Совместимость с GBC: - + SGB and GBC compatible: Совместимость с GBC и SGB: - + Game Boy palette Палитра Game Boy - + Default color palette only Только цветовая палитра по умолчанию - + SGB color palette if available Цветовая палитра SGB (если доступна) - + GBC color palette if available Цветовая палитра GBC (если доступна) - + SGB (preferred) or GBC color palette if available Цветовая палитра SGB (предпочтительно) или GBC (если доступны) - + Game Boy Camera - + Driver: Драйвер: - + Source: Источник: @@ -5024,12 +5295,12 @@ Download size: %3 Загружать из сохранения состояния: - + Enable VBA bug compatibility in ROM hacks Включить совместимость с VBA для ROM-хаков - + Preset: Пресет: @@ -5049,58 +5320,58 @@ Download size: %3 Показывать имя файла вместо названия ROM в заголовке окна - + Fast forward speed: Скорость перемотки: - - + + Unbounded Неограниченная - + Fast forward (held) speed: Скорость перемотки (на удержании): - + Autofire interval: Период автострельбы: - + Enable rewind Включить обратную перемотку - + Rewind history: История обратной перемотки: - + Idle loops: Холостые циклы: - + Run all Выполнять все - + Remove known Пропускать известные - + Detect and remove Обнаруживать и удалять - + Preload entire ROM into memory Загружать весь ROM в память заранее @@ -5117,149 +5388,150 @@ Download size: %3 Читы - + Enable Game Boy Player features by default Включить функции Game Boy Player по умолчанию - + Video renderer: Рендерер видео: - + Software Программный - + OpenGL enhancements Улучшения OpenGL - + High-resolution scale: Масштаб высокого разрешения: - + (240×160) - + (240×160) - + XQ GBA audio (experimental) Аудио XQ GBA (экспериментально) - + GB BIOS file: Файл GB BIOS: - - - - - - - - - + + + + + + + + + + Browse Открыть - + Use BIOS file if found Использовать файл BIOS, если найден - + Skip BIOS intro Пропустить интро BIOS - + GBA BIOS file: Файл GBA BIOS: - + GBC BIOS file: Файл GBC BIOS: - + SGB BIOS file: Файл SGB BIOS: - + Save games Сохранения - - - - - + + + + + Same directory as the ROM Директория, в которой находится ROM - + Save states Сохранения состояния - + Screenshots Скриншоты - + Patches Патчи - + Cheats Читы - + Log to file Сохранять журнал в файл - + Log to console Выводить на консоль - + Select Log File Выбрать файл журнала - + Default BG colors: Цвета фона по умолчанию: - + Super Game Boy borders Рамки Super Game Boy - + Default sprite colors 1: 1-е цвета по умолчанию для спрайта: - + Default sprite colors 2: 2-е цвета по умолчанию для спрайта: @@ -5272,27 +5544,28 @@ Download size: %3 Нет активных шейдеров - + + Load shader Загрузка шейдера - + No shader loaded Нет загруженных шейдеров - + by %1 автор %1 - + Preprocessing Предобработка - + Pass %1 Проход %1 @@ -5335,17 +5608,17 @@ Download size: %3 QGBA::ShortcutModel - + Action Действие - + Keyboard Клавиатура - + Gamepad Геймпад @@ -5465,17 +5738,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 Не удалось открыть выходной видеофайл: %1 - + Native (%0x%1) Нативно (%0x%1) - + Select output file Выбор выходного файла @@ -5518,7 +5791,7 @@ Download size: %3 WebM - + WebM @@ -5528,17 +5801,17 @@ Download size: %3 &1080p - + &1080p &720p - + &720p &480p - + &480p @@ -5553,18 +5826,18 @@ Download size: %3 MKV - + MKV AVI - + AVI MP4 - + MP4 @@ -5574,27 +5847,27 @@ Download size: %3 HEVC - + HEVC HEVC (NVENC) - + HEVC (NVENC) VP8 - + VP8 VP9 - + VP9 FFV1 - + FFV1 @@ -5605,17 +5878,17 @@ Download size: %3 FLAC - + FLAC WavPack - + WavPack Opus - + Opus @@ -5625,7 +5898,7 @@ Download size: %3 MP3 - + MP3 @@ -5686,100 +5959,80 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - Игры Game Boy Advance (%1) - - - - Game Boy ROMs (%1) - Игры Game Boy (%1) - - - - All ROMs (%1) - Все игры (%1) - - - - %1 Video Logs (*.mvl) - Журналы видео %1 (*.mvl) - - - + Archives (%1) Архивы (%1) - - - + + + Select ROM Выбор игры - + Select folder Выбор папки - - + + Select save Выбор сохранения - + Select patch Выбор патча - + Patches (*.ips *.ups *.bps) Патчи (*.ips *.ups *.bps) - + Select e-Reader dotcode Выбор карточки e-Reader - + e-Reader card (*.raw *.bin *.bmp) Карточка e-Reader (*.raw *.bin *.bmp) - + Select image Выбор изображения - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Файл изображения (*.png *.gif *.jpg *.jpeg);;All files (*) - + GameShark saves (*.sps *.xps) Сохранения GameShark (*.sps *.xps) - + Select video log Выбор видеолога - + Video logs (*.mvl) Видеологи (*.mvl) - + Crash Сбой - + The game has crashed with the following error: %1 @@ -5788,740 +6041,770 @@ Download size: %3 %1 - + Couldn't Start Запуск не удался - + Could not start game. Не удалось запустить игру. - + Unimplemented BIOS call Неизвестный вызов BIOS - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Игра использует нереализованный вызов BIOS. Пожалуйста, воспользуйтесь официальным BIOS для лучшей совместимости. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Не удалось создать устройство отображения, возврат к программному режиму. Игры могут идти медленнее, особенно в окнах больших размеров. - + Really make portable? Перейти в портативный режим? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? После этого эмулятор будет загружать конфигурацию из папки с исполняемым файлом. Продолжить? - + Restart needed Требуется перезапуск - + Some changes will not take effect until the emulator is restarted. Для применения некоторых изменений требуется перезапустить эмулятор. - + - Player %1 of %2 - Игрок %1 из %2 - + %1 - %2 - + %1 - %2 - + %1 - %2 - %3 - + %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File &Файл - + Load &ROM... Загрузить &ROM... - + Load ROM in archive... Загрузить игру из архива... - + Add folder to library... Добавить папку в библиотеку... - + Save games (%1) Игровые сохранения (%1) - + Select save game Выбор игрового сохранения - + mGBA save state files (%1) Файл сохранения состояния mGBA (%1) - - + + Select save state Выбор сохранения состояния - + Select e-Reader card images Выбор изображения карточки e-Reader - + Image file (*.png *.jpg *.jpeg) Файл изображения (*.png *.jpg *.jpeg) - + Conversion finished Конвертация завершена - + %1 of %2 e-Reader cards converted successfully. %1 из %2 карточек e-Reader успешно сконвертировано. - + Load alternate save game... Загрузить альтернативное сохранение... - + Load temporary save game... Загрузить временное сохранение... - + Load &patch... Загрузить &патч... - + Boot BIOS Загрузиться в BIOS - + Replace ROM... Заменить ROM... - + Scan e-Reader dotcodes... Сканировать dot-коды e-Reader... - + Convert e-Reader card image to raw... Конвертировать карту e-Reader в raw... - + ROM &info... Информация об &игре... - + Recent Недавние - + Make portable Портативный режим - + &Load state &Загрузить состояние - + Load state file... Загрузить состояние из файла... - + &Save state &Сохранить состояние - + Save state file... Сохранить состояние в файл... - + Quick load Быстрая загрузка - + Quick save Быстрое сохранение - + Load recent Загрузить недавнее - + Save recent Сохранить в недавнее - + Undo load state Отмена загрузки состояния - + Undo save state Отмена сохранения состояния - - + + State &%1 Слот &%1 - + Load camera image... Загрузить изображение с камеры... - + Convert save game... Конвертировать игровое сохранение... - + GameShark saves (*.gsv *.sps *.xps) Сохранения GameShark (*.gsv *.sps *.xps) - + Reset needed Необходима перезагрузка - + Some changes will not take effect until the game is reset. Некоторые изменения не войдут в силу, пока игра не перезагружена. - + Save games Сохранения - + Import GameShark Save... Импорт сохранения GameShark... - + Export GameShark Save... Экспорт сохранения GameShark... - + Automatically determine Определить автоматически - + Use player %0 save game Использовать сохранение игрока %0 - + New multiplayer window Новое окно мультиплеера - + Connect to Dolphin... Соединение с Dolphin... - + Report bug... Сообщить об ошибке... - + About... О программе... - + E&xit &Выход - + &Emulation &Эмуляция - + &Reset Перезагрузить (&R/&К) - + Sh&utdown Выключить (&U/&Г) - + Yank game pak Пнуть картридж - + &Pause Пау&за - + &Next frame Следующий кадр (&N/&Т) - + Fast forward (held) Перемотка (удержание) - + &Fast forward Перемотк&а - + Fast forward speed Скорость перемотки - + Unbounded Неограниченная - + %0x - %0x + %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) Обратная перемотка (удержание) - + Re&wind Обратная перемотка (&W/&Ц) - + Step backwards Шаг назад - + Solar sensor Датчик солнца - + Increase solar level Усилить солнечный свет - + Decrease solar level Ослабить солнечный свет - + Brightest solar level Ярчайшее солнце - + Darkest solar level Тусклейшее солнце - + Brightness %1 Яркость %1 - + Game Boy Printer... - + BattleChip Gate... - + Audio/&Video Аудио/Видео (&V/&М) - + Frame size Размер кадра - + %1× - %1× + %1× - + Toggle fullscreen Переключить полноэкранный режим - + Lock aspect ratio Зафиксировать соотношение сторон - + Force integer scaling Принудительное целочисленное масштабирование - + Interframe blending Межкадровое смешение - + Bilinear filtering Билинейная фильтрация - + Frame&skip Пропуск кадров (&S/&Ы) - + Mute Выключить звук - + FPS target Целевой FPS - + Native (59.7275) Родной (59.7275) - + Take &screenshot Снять скриншот (&S/&Ы) - + F12 - + F12 - + Record A/V... Записать аудио/видео... - + Record GIF/WebP/APNG... Записать GIF/WebP/APNG... - + Video layers Видеослои - + Audio channels Аудиоканалы - + Adjust layer placement... Настроить расположение слоёв... - + &Tools Инструм&енты - + View &logs... Посмотреть в журнал... (&L/&Д) - + Game &overrides... Переопределения для этой игры... (&О/&Щ) - + Game Pak sensors... Датчики в Game Pak... - + &Cheats... Читы... (&C/&С) - + + Create forwarder... + + + + Settings... Настройки... - + Open debugger console... Открыть консоль отладки... - + Start &GDB server... Запустить сервер &GDB... - + Scripting... Скрипты... - + Game state views Просмотр состояния игры - + View &palette... Просмотр палитры... (&P/&З) - + View &sprites... Просмотр спрайтов... (&S/&Ы) - + View &tiles... Просмотр тайлов... (&T/&Е) - + View &map... Просмотр карты... (&M/&Ь) - + &Frame inspector... Изучение фрейм&а... - + View memory... Просмотр памяти... - + Search memory... Поиск в памяти... - + View &I/O registers... Просмотр регистров &I/O... - + Record debug video log... Запись отладочного видеожурнала... - + Stop debug video log Закончить запись отладочного видеожурнала - + Exit fullscreen Выйти из полноэкранного режима - + GameShark Button (held) Кнопка GameShark (удерживается) - + Autofire Автострельба - + Autofire A A (автострельба) - + Autofire B B (автострельба) - + Autofire L L (автострельба) - + Autofire R R (автострельба) - + Autofire Start Start (автострельба) - + Autofire Select Select (автострельба) - + Autofire Up Вверх (автострельба) - + Autofire Right Вправо (автострельба) - + Autofire Down Вниз (автострельба) - + Autofire Left Влево (автострельба) - + Clear - Очистить + Очистить QObject - + %1 byte %1 байт - + %1 kiB - + %1 MiB - + GBA - + GBA - + GB + GB + + + + ? + ? + + + + Super (L) - - ? + + Super (R) + + + Menu + Меню + QShortcut - + Shift - + Control - + Alt - + Meta diff --git a/src/platform/qt/ts/mgba-sv.ts b/src/platform/qt/ts/mgba-sv.ts new file mode 100644 index 000000000..55df22b52 --- /dev/null +++ b/src/platform/qt/ts/mgba-sv.ts @@ -0,0 +1,6808 @@ + + + + + QGBA + + + Game Boy Advance ROMs (%1) + + + + + Game Boy ROMs (%1) + + + + + All ROMs (%1) + + + + + %1 Video Logs (*.mvl) + + + + + QGBA::AboutScreen + + + About + Om mGBA + + + + <a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Forums / Support</a> • <a href="https://patreon.com/mgba">Donate</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Source</a> + <a href="http://mgba.io/">Hemsida</a> • <a href="https://forums.mgba.io/">Forum / Hjälp</a> • <a href="https://patreon.com/mgba">Stödja mGBA</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Källkod</a> + + + + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + + + + {projectName} would like to thank the following patrons from Patreon: + {projectName} tackar följande donatorer från Patreon: + + + + © 2013 – {year} Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + © 2013 – {year} Jeffrey Pfau, licensierad under Mozilla Public License, version 2.0 +Game Boy Advance är ett registrerat varumärke av Nintendo Co., Ltd. + + + + {projectName} is an open-source Game Boy Advance emulator + {projectName} är en emulator för Game Boy Advance, byggt på öppen källkod + + + + QGBA::ApplicationUpdatePrompt + + + An update is available + En uppdatering är tillgänglig + + + + An update to %1 is available. + + En uppdatering till %1 är tillgänglig. + + + + + +Do you want to download and install it now? You will need to restart the emulator when the download is complete. + +Vill du ladda ner och installera det nu? Programmet måste startas om när nedladdningen är klar. + + + + +Auto-update is not available on this platform. If you wish to update you will need to do it manually. + +Det finns ej automatiska uppdateringar för detta operativ system. Önskar du uppdatera programmet måste du göra det manuellt. + + + + Current version: %1 +New version: %2 +Download size: %3 + Nuvarande version: %1 +Nästa version: %2 +Nedladdningsstorlek: %3 + + + + Downloading update... + Uppdatering laddas ner... + + + + Downloading failed. Please update manually. + Nedladdningen misslyckades. Uppdateringen måste installeras manuellt. + + + + Downloading done. Press OK to restart %1 and install the update. + Nedladdning klar. Välj OK för att starta om %1 och installera uppdateringen. + + + + QGBA::ApplicationUpdater + + + Stable + Standard + + + + Development + Utveckling + + + + Unknown + Okänd + + + + (None) + (Inga) + + + + QGBA::ArchiveInspector + + + Open in archive... + Öppna i arkiveringsprogram... + + + + Loading... + Laddas... + + + + QGBA::AssetTile + + + Tile # + Tile # + + + + Palette # + Palette # + + + + Address + Adress + + + + Red + Röd + + + + Green + Grön + + + + Blue + Blå + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + QGBA::AudioDevice + + + Can't set format of context-less audio device + Det går inte att ställa in formatet för kontextlös ljudenhet + + + + Audio device is missing its core + Ljudenheten saknar kärnan + + + + Writing data to read-only audio device + Skriver data till skrivskyddad ljudenhet + + + + QGBA::AudioProcessorQt + + + Can't start an audio processor without input + Kan inte starta en ljudprocessor utan ingång + + + + QGBA::AudioProcessorSDL + + + Can't start an audio processor without input + Kan inte starta en ljudprocessor utan ingång + + + + QGBA::BattleChipView + + + BattleChip Gate + BattleChip Gate + + + + Chip name + Chip namn + + + + Insert + Infoga + + + + Save + Spara + + + + Load + Ladda + + + + Add + Lägg till + + + + Remove + Ta bort + + + + Gate type + Gate typ + + + + Inserted + Infogad + + + + Chip ID + Chip ID + + + + Update Chip data + Uppdatera Chip-data + + + + Show advanced + Visa avancerat + + + + BattleChip data missing + BattleChip-data saknas + + + + BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? + BattleChip-data saknas. BattleChip Gates fungerar fortfarande, men viss grafik kommer att saknas. Vill du ladda ner datan nu? + + + + + Select deck file + Välj deck-fil + + + + Incompatible deck + Inkompatibelt deck + + + + The selected deck is not compatible with this Chip Gate + Den valda deck är inte kompatibel med denna Chip Gate + + + + QGBA::CheatsModel + + + (untitled) + (saknar namn) + + + + Failed to open cheats file: %1 + Misslyckades att öppna cheats-filen: %1 + + + + QGBA::CheatsView + + + Cheats + Cheats + + + + Add New Code + Lägg till ny kod + + + + Remove + Ta bort + + + + Add Lines + + + + + Code type + + + + + Save + Spara + + + + Load + Ladda + + + + Enter codes here... + + + + + + Autodetect (recommended) + + + + + + Select cheats file + + + + + Some cheats could not be added. Please ensure they're formatted correctly and/or try other cheat types. + + + + + QGBA::CoreController + + + Reset r%1-%2 %3 + + + + + + Rewinding not currently enabled + + + + + Reset the game? + + + + + Most games will require a reset to load the new save. Do you want to reset now? + + + + + Failed to open save file: %1 + + + + + Failed to open game file: %1 + + + + + Can't yank pack in unexpected platform! + + + + + Failed to open snapshot file for reading: %1 + + + + + Failed to open snapshot file for writing: %1 + + + + + QGBA::CoreManager + + + Failed to open game file: %1 + + + + + Could not load game. Are you sure it's in the correct format? + + + + + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). + + + + + QGBA::DebuggerConsole + + + Debugger + + + + + Enter command (try `help` for more info) + + + + + Break + + + + + QGBA::DebuggerConsoleController + + + Could not open CLI history for writing + + + + + QGBA::DolphinConnector + + + Connect to Dolphin + + + + + Local computer + + + + + IP address + + + + + Connect + + + + + Disconnect + + + + + Close + + + + + Reset on connect + + + + + Couldn't Connect + + + + + Could not connect to Dolphin. + + + + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + + + QGBA::FrameView + + + Inspect frame + + + + + Magnification + + + + + Freeze frame + + + + + Backdrop color + + + + + Disable scanline effects + + + + + Export + + + + + Reset + + + + + Export frame + + + + + Portable Network Graphics (*.png) + + + + + None + + + + + Background + + + + + Window + + + + + Objwin + + + + + Sprite + + + + + Backdrop + + + + + Frame + + + + + %1 %2 + + + + + QGBA::GBAApp + + + Enable Discord Rich Presence + + + + + QGBA::GBAKeyEditor + + + Clear Button + + + + + Clear Analog + + + + + Refresh + + + + + Set all + + + + + QGBA::GDBWindow + + + Server settings + + + + + Local port + + + + + Bind address + + + + + Write watchpoints behavior + + + + + Standard GDB + + + + + Internal change detection + + + + + Break on all writes + + + + + Break + + + + + Stop + + + + + Start + + + + + Crash + + + + + Could not start GDB server + + + + + QGBA::GIFView + + + Record GIF/WebP/APNG + + + + + Loop + + + + + Start + + + + + Stop + + + + + Select File + + + + + APNG + + + + + GIF + + + + + WebP + + + + + Frameskip + + + + + Failed to open output file: %1 + + + + + Select output file + + + + + Graphics Interchange Format (*.gif);;WebP ( *.webp);;Animated Portable Network Graphics (*.png *.apng) + + + + + QGBA::GameBoy + + + + Autodetect + + + + + Game Boy (DMG) + + + + + Game Boy Pocket (MGB) + + + + + Super Game Boy (SGB) + + + + + Super Game Boy 2 (SGB) + + + + + Game Boy Color (CGB) + + + + + Game Boy Advance (AGB) + + + + + Super Game Boy Color (SGB + CGB) + + + + + ROM Only + + + + + MBC1 + + + + + MBC2 + + + + + MBC3 + + + + + MBC3 + RTC + + + + + MBC5 + + + + + MBC5 + Rumble + + + + + MBC6 + + + + + MBC7 (Tilt) + + + + + MMM01 + + + + + HuC-1 + + + + + HuC-3 + + + + + Pocket Cam + + + + + TAMA5 + + + + + Wisdom Tree + + + + + NT (old 1) + + + + + NT (old 2) + + + + + NT (new) + + + + + Pokémon Jade/Diamond + + + + + BBD + + + + + Hitek + + + + + GGB-81 + + + + + Li Cheng + + + + + Sachen (MMC1) + + + + + Sachen (MMC2) + + + + + QGBA::IOViewer + + + I/O Viewer + + + + + 0x0000 + + + + + + + B + + + + + Background mode + + + + + Mode 0: 4 tile layers + + + + + Mode 1: 2 tile layers + 1 rotated/scaled tile layer + + + + + Mode 2: 2 rotated/scaled tile layers + + + + + Mode 3: Full 15-bit bitmap + + + + + Mode 4: Full 8-bit bitmap + + + + + Mode 5: Small 15-bit bitmap + + + + + CGB Mode + + + + + Frame select + + + + + Unlocked HBlank + + + + + Linear OBJ tile mapping + + + + + Force blank screen + + + + + Enable background 0 + + + + + Enable background 1 + + + + + Enable background 2 + + + + + Enable background 3 + + + + + Enable OBJ + + + + + Enable Window 0 + + + + + Enable Window 1 + + + + + Enable OBJ Window + + + + + Swap green components + + + + + Currently in VBlank + + + + + Currently in HBlank + + + + + Currently in VCounter + + + + + Enable VBlank IRQ generation + + + + + Enable HBlank IRQ generation + + + + + Enable VCounter IRQ generation + + + + + VCounter scanline + + + + + Current scanline + + + + + + + + Priority + + + + + + + + Tile data base (* 16kB) + + + + + + + + Enable mosaic + + + + + + + + Enable 256-color + + + + + + + + Tile map base (* 2kB) + + + + + + + + Background dimensions + + + + + + Overflow wraps + + + + + + + + + + Horizontal offset + + + + + + + + + + Vertical offset + + + + + + + + + + + + + + + + Fractional part + + + + + + + + + + + + Integer part + + + + + + + + Integer part (low) + + + + + + + + Integer part (high) + + + + + + End x + + + + + + Start x + + + + + + End y + + + + + + Start y + + + + + Window 0 enable BG 0 + + + + + Window 0 enable BG 1 + + + + + Window 0 enable BG 2 + + + + + Window 0 enable BG 3 + + + + + Window 0 enable OBJ + + + + + Window 0 enable blend + + + + + Window 1 enable BG 0 + + + + + Window 1 enable BG 1 + + + + + Window 1 enable BG 2 + + + + + Window 1 enable BG 3 + + + + + Window 1 enable OBJ + + + + + Window 1 enable blend + + + + + Outside window enable BG 0 + + + + + Outside window enable BG 1 + + + + + Outside window enable BG 2 + + + + + Outside window enable BG 3 + + + + + Outside window enable OBJ + + + + + Outside window enable blend + + + + + OBJ window enable BG 0 + + + + + OBJ window enable BG 1 + + + + + OBJ window enable BG 2 + + + + + OBJ window enable BG 3 + + + + + OBJ window enable OBJ + + + + + OBJ window enable blend + + + + + Background mosaic size vertical + + + + + Background mosaic size horizontal + + + + + Object mosaic size vertical + + + + + Object mosaic size horizontal + + + + + BG 0 target 1 + + + + + BG 1 target 1 + + + + + BG 2 target 1 + + + + + BG 3 target 1 + + + + + OBJ target 1 + + + + + Backdrop target 1 + + + + + Blend mode + + + + + Disabled + + + + + Additive blending + + + + + Brighten + + + + + Darken + + + + + BG 0 target 2 + + + + + BG 1 target 2 + + + + + BG 2 target 2 + + + + + BG 3 target 2 + + + + + OBJ target 2 + + + + + Backdrop target 2 + + + + + Blend A (target 1) + + + + + Blend B (target 2) + + + + + Blend Y + + + + + + Sweep shifts + + + + + + Sweep subtract + + + + + + Sweep time (in 1/128s) + + + + + + + + + + + + Sound length + + + + + + + + Duty cycle + + + + + + + + + + Envelope step time + + + + + + + + + + Envelope increase + + + + + + + + + + Initial volume + + + + + + + Sound frequency + + + + + + + + + + + + Timed + + + + + + + + + + + + Reset + + + + + Double-size wave table + + + + + Active wave table + + + + + + Enable channel 3 + + + + + + Volume + + + + + + 0% + + + + + + + 100% + + + + + + + 50% + + + + + + + 25% + + + + + + + + 75% + + + + + + Clock divider + + + + + + Register stages + + + + + + 15 + + + + + + 7 + + + + + + Shifter frequency + + + + + PSG volume right + + + + + PSG volume left + + + + + + Enable channel 1 right + + + + + + Enable channel 2 right + + + + + + Enable channel 3 right + + + + + + Enable channel 4 right + + + + + + Enable channel 1 left + + + + + + Enable channel 2 left + + + + + + Enable channel 3 left + + + + + + Enable channel 4 left + + + + + PSG master volume + + + + + Loud channel A + + + + + Loud channel B + + + + + Enable channel A right + + + + + Enable channel A left + + + + + Channel A timer + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + Channel A reset + + + + + Enable channel B right + + + + + Enable channel B left + + + + + Channel B timer + + + + + Channel B reset + + + + + + Active channel 1 + + + + + + Active channel 2 + + + + + + Active channel 3 + + + + + + Active channel 4 + + + + + + Enable audio + + + + + Bias + + + + + Resolution + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample + + + + + + + + + + + + Address (low) + + + + + + + + + + + + Address (high) + + + + + + + Sound frequency (low) + + + + + + + Sound frequency (high) + + + + + Source (high) + + + + + Source (low) + + + + + Destination (high) + + + + + Destination (low) + + + + + + Green (low) + + + + + + Green (high) + + + + + + + + Word count + + + + + + + + Destination offset + + + + + + + + + + + + Increment + + + + + + + + + + + + Decrement + + + + + + + + + + + + Fixed + + + + + + + + Increment and reload + + + + + + + + Source offset + + + + + + + + Repeat + + + + + + + + 32-bit + + + + + + + + Start timing + + + + + + + + + Immediate + + + + + + + + + + + + VBlank + + + + + + + + + + + HBlank + + + + + + + + + + + + + IRQ + + + + + + + + + + + + + + + Enable + + + + + + + Audio FIFO + + + + + Video Capture + + + + + DRQ + + + + + + + + + + + + Value + + + + + + + + Scale + + + + + + + + + 1/64 + + + + + + + + + 1/256 + + + + + + + + + 1/1024 + + + + + + + Cascade + + + + + + A + + + + + + Select + + + + + + Start + + + + + + Right + + + + + + Left + + + + + + Up + + + + + + Down + + + + + + R + + + + + + L + + + + + Condition + + + + + SC + + + + + SD + + + + + SI + + + + + SO + + + + + + VCounter + + + + + + Timer 0 + + + + + + Timer 1 + + + + + + Timer 2 + + + + + + Timer 3 + + + + + + SIO + + + + + + DMA 0 + + + + + + DMA 1 + + + + + + DMA 2 + + + + + + DMA 3 + + + + + + Keypad + + + + + + Gamepak + + + + + SRAM wait + + + + + + + + + 4 + + + + + + + + 3 + + + + + + + + + 2 + + + + + + + + + 8 + + + + + Cart 0 non-sequential + + + + + Cart 0 sequential + + + + + Cart 1 non-sequential + + + + + Cart 1 sequential + + + + + Cart 2 non-sequential + + + + + Cart 2 sequential + + + + + PHI terminal + + + + + + Disable + + + + + 4.19MHz + + + + + 8.38MHz + + + + + 16.78MHz + + + + + Gamepak prefetch + + + + + Enable IRQs + + + + + Right/A + + + + + Left/B + + + + + Up/Select + + + + + Down/Start + + + + + Active D-pad + + + + + Active face buttons + + + + + Internal clock + + + + + 32× clocking (CGB only) + + + + + Transfer active + + + + + Divider + + + + + 1/16 + + + + + + LCD STAT + + + + + + Timer + + + + + + Serial + + + + + + Joypad + + + + + Volume right + + + + + Output right + + + + + Volume left + + + + + Output left + + + + + Background enable/priority + + + + + Enable sprites + + + + + Double-height sprites + + + + + Background tile map + + + + + + 0x9800 – 0x9BFF + + + + + + 0x9C00 – 0x9FFF + + + + + Background tile data + + + + + 0x8800 – 0x87FF + + + + + 0x8000 – 0x8FFF + + + + + Enable window + + + + + Window tile map + + + + + Enable LCD + + + + + Mode + + + + + 0: HBlank + + + + + 1: VBlank + + + + + 2: OAM scan + + + + + 3: HDraw + + + + + In LYC + + + + + Enable HBlank (mode 0) IRQ + + + + + Enable VBlank (mode 1) IRQ + + + + + Enable OAM (mode 2) IRQ + + + + + Enable LYC IRQ + + + + + Current Y coordinate + + + + + Comparison Y coordinate + + + + + Start upper byte + + + + + + + Color 0 shade + + + + + + + Color 1 shade + + + + + + + Color 2 shade + + + + + + + Color 3 shade + + + + + Prepare to switch speed + + + + + Double speed + + + + + VRAM bank + + + + + Length + + + + + Timing + + + + + Write bit + + + + + Read bit + + + + + + Unknown + Okänd + + + + + Current index + + + + + + Auto-increment + + + + + + Red + Röd + + + + + Blue + Blå + + + + Sprite ordering + + + + + OAM order + + + + + x coordinate sorting + + + + + WRAM bank + + + + + QGBA::KeyEditor + + + + --- + + + + + QGBA::LibraryTree + + + Name + + + + + Location + + + + + Platform + + + + + Size + + + + + CRC32 + + + + + QGBA::LoadSaveState + + + + %1 State + + + + + + + + + + + + + No Save + + + + + 5 + + + + + 6 + + + + + 8 + + + + + 4 + + + + + 1 + + + + + 3 + + + + + 7 + + + + + 9 + + + + + 2 + + + + + Cancel + + + + + Load State + + + + + Save State + + + + + Empty + + + + + Corrupted + + + + + Slot %1 + + + + + QGBA::LogConfigModel + + + + Default + + + + + Fatal + + + + + Error + + + + + Warning + + + + + Info + + + + + Debug + + + + + Stub + + + + + Game Error + + + + + QGBA::LogController + + + [%1] %2: %3 + + + + + An error occurred + + + + + DEBUG + + + + + STUB + + + + + INFO + + + + + WARN + + + + + ERROR + + + + + FATAL + + + + + GAME ERROR + + + + + QGBA::LogView + + + Logs + + + + + Enabled Levels + + + + + Debug + + + + + Stub + + + + + Info + + + + + Warning + + + + + Error + + + + + Fatal + + + + + Game Error + + + + + Advanced settings + + + + + Clear + + + + + Max Lines + + + + + QGBA::MapView + + + Maps + + + + + Magnification + + + + + Export + + + + + Copy + + + + + Priority + + + + + + Map base + + + + + + Tile base + + + + + Size + + + + + + Offset + + + + + Xform + + + + + Map Addr. + + + + + Mirror + + + + + None + + + + + Both + + + + + Horizontal + + + + + Vertical + + + + + + + N/A + + + + + Export map + + + + + Portable Network Graphics (*.png) + + + + + QGBA::MemoryDump + + + Save Memory Range + + + + + Start Address: + + + + + Byte Count: + + + + + Dump across banks + + + + + Save memory region + + + + + Failed to open output file: %1 + + + + + QGBA::MemoryModel + + + Copy selection + + + + + Save selection + + + + + Paste + + + + + Load + Ladda + + + + All + + + + + Load TBL + + + + + Save selected memory + + + + + Failed to open output file: %1 + + + + + Load memory + + + + + Failed to open input file: %1 + + + + + TBL + + + + + ISO-8859-1 + + + + + QGBA::MemorySearch + + + Memory Search + + + + + Address + Adress + + + + Current Value + + + + + + Type + + + + + Value + + + + + Numeric + + + + + Text + + + + + Width + + + + + + Guess + + + + + 1 Byte (8-bit) + + + + + 2 Bytes (16-bit) + + + + + 4 Bytes (32-bit) + + + + + Number type + + + + + Decimal + + + + + Hexadecimal + + + + + Search type + + + + + Equal to value + + + + + Greater than value + + + + + Less than value + + + + + Unknown/changed + + + + + Changed by value + + + + + Unchanged + + + + + Increased + + + + + Decreased + + + + + Search ROM + + + + + New Search + + + + + Search Within + + + + + Open in Memory Viewer + + + + + Refresh + + + + + (%0/%1×) + + + + + (⅟%0×) + + + + + (%0×) + + + + + %1 byte%2 + + + + + QGBA::MemoryView + + + Memory + + + + + Inspect Address: + + + + + Set Alignment: + + + + + &1 Byte + + + + + &2 Bytes + + + + + &4 Bytes + + + + + Unsigned Integer: + + + + + Signed Integer: + + + + + String: + + + + + Load TBL + + + + + Copy Selection + + + + + Paste + + + + + Save Selection + + + + + Save Range + + + + + Load + Ladda + + + + QGBA::MessagePainter + + + Frame %1 + + + + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + + + QGBA::ObjView + + + Sprites + + + + + Address + Adress + + + + Copy + + + + + Magnification + + + + + Geometry + + + + + Position + + + + + Dimensions + + + + + Matrix + + + + + Export + + + + + Attributes + + + + + Transform + + + + + + Off + + + + + Palette + + + + + Double Size + + + + + + + Return, Ctrl+R + + + + + Flipped + + + + + H + Short for horizontal + + + + + V + Short for vertical + + + + + Mode + + + + + + Normal + + + + + Mosaic + + + + + Enabled + + + + + Priority + + + + + Tile + + + + + + 0x%0 + + + + + + + + + + + + --- + + + + + Trans + + + + + OBJWIN + + + + + Invalid + + + + + + N/A + + + + + Export sprite + + + + + Portable Network Graphics (*.png) + + + + + QGBA::OverrideView + + + Game Overrides + + + + + Game Boy Advance + + + + + + + + Autodetect + + + + + Realtime clock + + + + + Gyroscope + + + + + Tilt + + + + + Light sensor + + + + + Rumble + + + + + Save type + + + + + None + + + + + SRAM + + + + + Flash 512kb + + + + + Flash 1Mb + + + + + EEPROM 8kB + + + + + EEPROM 512 bytes + + + + + SRAM 64kB (bootlegs only) + + + + + Idle loop + + + + + Game Boy Player features + + + + + VBA bug compatibility mode + + + + + Game Boy + + + + + Game Boy model + + + + + Memory bank controller + + + + + Background Colors + + + + + Sprite Colors 1 + + + + + Sprite Colors 2 + + + + + Palette preset + + + + + Official MBCs + + + + + Licensed MBCs + + + + + Unlicensed MBCs + + + + + QGBA::PaletteView + + + Palette + + + + + Background + + + + + Objects + + + + + Selection + + + + + Red + Röd + + + + Green + Grön + + + + Blue + Blå + + + + 16-bit value + + + + + Hex code + + + + + Palette index + + + + + Export BG + + + + + Export OBJ + + + + + #%0 + + + + + 0x%0 + + + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + Export palette + + + + + Windows PAL (*.pal);;Adobe Color Table (*.act) + + + + + Failed to open output palette file: %1 + + + + + QGBA::PlacementControl + + + Adjust placement + + + + + All + + + + + Offset + + + + + X + + + + + Y + + + + + QGBA::PrinterView + + + Game Boy Printer + + + + + Hurry up! + + + + + Tear off + + + + + Magnification + + + + + Copy + + + + + Save Printout + + + + + Portable Network Graphics (*.png) + + + + + QGBA::ROMInfo + + + + + + + (unknown) + + + + + bytes + + + + + (no database present) + + + + + ROM Info + + + + + Game name: + + + + + Internal name: + + + + + Game ID: + + + + + File size: + + + + + CRC32: + + + + + Save file: + + + + + QGBA::ReportView + + + Bug report archive + + + + + ZIP archive (*.zip) + + + + + Generate Bug Report + + + + + <html><head/><body><p>To file a bug report, please first generate a report file to attach to the bug report you're about to file. It is recommended that you include the save files, as these often help with debugging issues. This will collect some information about the version of {projectName} you're running, your configuration, your computer, and the game you currently have open (if any). Once this collection is completed you can review all of the information gathered below and save it to a zip file. The collection will automatically attempt to redact any personal information, such as your username if it's in any of the paths gathered, but just in case you can edit it afterwards. After you have generated and saved it, please click the button below or go to <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> to file the bug report on GitHub. Make sure to attach the report you generated!</p></body></html> + + + + + Generate report + + + + + Save + Spara + + + + Open issue list in browser + + + + + Include save file + + + + + Create and include savestate + + + + + QGBA::SaveConverter + + + Save games and save states (%1) + + + + + Select save game or save state + + + + + Save games (%1) + + + + + Select save game + + + + + Conversion failed + + + + + Failed to convert the save game. This is probably a bug. + + + + + No file selected + + + + + Could not open file + + + + + No valid formats found + + + + + Please select a valid input file + + + + + No valid conversions found + + + + + Cannot convert save games between platforms + + + + + Convert/Extract Save Game + + + + + Input file + + + + + + Browse + + + + + Output file + + + + + %1 %2 save game + + + + + little endian + + + + + big endian + + + + + SRAM + + + + + %1 flash + + + + + %1 EEPROM + + + + + + RTC + + + + + %1 SRAM + RTC + + + + + %1 SRAM + + + + + packed MBC2 + + + + + unpacked MBC2 + + + + + MBC6 flash + + + + + MBC6 combined SRAM + flash + + + + + MBC6 SRAM + + + + + TAMA5 + + + + + %1 (%2) + + + + + %1 save state with embedded %2 save game + + + + + %1 SharkPort %2 save game + + + + + %1 GameShark Advance SP %2 save game + + + + + QGBA::ScriptingTextBuffer + + + Untitled buffer + + + + + QGBA::ScriptingView + + + Scripting + + + + + Run + + + + + File + + + + + Load recent script + + + + + Load script... + + + + + &Reset + + + + + 0 + + + + + Select script to load + + + + + Lua scripts (*.lua) + + + + + All files (*.*) + + + + + QGBA::SensorView + + + Sensors + + + + + Realtime clock + + + + + Fixed time + + + + + System time + + + + + Start time at + + + + + Now + + + + + Offset time + + + + + sec + + + + + MM/dd/yy hh:mm:ss AP + + + + + Light sensor + + + + + Brightness + + + + + Tilt sensor + + + + + + Set Y + + + + + + Set X + + + + + Gyroscope + + + + + Sensitivity + + + + + QGBA::SettingsView + + + + Qt Multimedia + + + + + SDL + + + + + Software (Qt) + + + + + + OpenGL + + + + + OpenGL (force version 1.x) + + + + + None + + + + + None (Still Image) + + + + + Keyboard + + + + + Controllers + + + + + Shortcuts + + + + + + Shaders + + + + + Select BIOS + + + + + Select directory + + + + + Select image + + + + + Image file (*.png *.jpg *.jpeg) + + + + + (%1×%2) + + + + + Never + + + + + Just now + + + + + Less than an hour ago + + + + + %n hour(s) ago + + + + + + + + %n day(s) ago + + + + + + + + Settings + + + + + Audio/Video + + + + + Gameplay + + + + + Interface + + + + + Update + + + + + Emulation + + + + + Enhancements + + + + + BIOS + + + + + Paths + + + + + Logging + + + + + Game Boy + + + + + Audio driver: + + + + + Audio buffer: + + + + + + 1536 + + + + + 512 + + + + + 768 + + + + + 1024 + + + + + 2048 + + + + + 3072 + + + + + 4096 + + + + + samples + + + + + Sample rate: + + + + + + 44100 + + + + + 22050 + + + + + 32000 + + + + + 48000 + + + + + Hz + + + + + Volume: + + + + + + + + Mute + + + + + Fast forward volume: + + + + + Audio in multiplayer: + + + + + All windows + + + + + Player 1 window only + + + + + Currently active player window + + + + + Display driver: + + + + + Frameskip: + + + + + Skip every + + + + + + frames + + + + + FPS target: + + + + + frames per second + + + + + Sync: + + + + + + Video + + + + + + Audio + + + + + Lock aspect ratio + + + + + Force integer scaling + + + + + Bilinear filtering + + + + + Show filename instead of ROM name in library view + + + + + + Pause + + + + + When inactive: + + + + + On loading a game: + + + + + Load last state + + + + + Load cheats + + + + + Save entered cheats + + + + + When minimized: + + + + + Current channel: + + + + + Current version: + + + + + Update channel: + + + + + Available version: + + + + + (Unknown) + + + + + Last checked: + + + + + Automatically check on start + + + + + Check now + + + + + Default color palette only + + + + + SGB color palette if available + + + + + GBC color palette if available + + + + + SGB (preferred) or GBC color palette if available + + + + + Game Boy Camera + + + + + Driver: + + + + + Source: + + + + + Native (59.7275) + + + + + Interframe blending + + + + + Language + + + + + Library: + + + + + List view + + + + + Tree view + + + + + Show when no game open + + + + + Clear cache + + + + + Allow opposing input directions + + + + + Suspend screensaver + + + + + Dynamically update window title + + + + + Show filename instead of ROM name in title bar + + + + + Show OSD messages + + + + + Enable Discord Rich Presence + + + + + Periodically autosave state + + + + + Show FPS in title bar + + + + + Show frame count in OSD + + + + + Show emulation info on reset + + + + + Custom border: + + + + + Fast forward speed: + + + + + + Unbounded + + + + + Fast forward (held) speed: + + + + + Autofire interval: + + + + + Enable rewind + + + + + Rewind history: + + + + + Rewind speed: + + + + + Idle loops: + + + + + Run all + + + + + Remove known + + + + + Detect and remove + + + + + Preload entire ROM into memory + + + + + Save state extra data: + + + + + + Save game + + + + + Load state extra data: + + + + + Models + + + + + GB only: + + + + + SGB compatible: + + + + + GBC only: + + + + + GBC compatible: + + + + + SGB and GBC compatible: + + + + + Game Boy palette + + + + + Preset: + + + + + + Screenshot + + + + + + Cheat codes + + + + + Enable Game Boy Player features by default + + + + + Enable VBA bug compatibility in ROM hacks + + + + + Video renderer: + + + + + Software + + + + + OpenGL enhancements + + + + + High-resolution scale: + + + + + (240×160) + + + + + XQ GBA audio (experimental) + + + + + GB BIOS file: + + + + + + + + + + + + + + Browse + + + + + Use BIOS file if found + + + + + Skip BIOS intro + + + + + GBA BIOS file: + + + + + GBC BIOS file: + + + + + SGB BIOS file: + + + + + Save games + + + + + + + + + Same directory as the ROM + + + + + Save states + + + + + Screenshots + + + + + Patches + + + + + Cheats + Cheats + + + + Log to file + + + + + Log to console + + + + + Select Log File + + + + + Default BG colors: + + + + + Default sprite colors 1: + + + + + Default sprite colors 2: + + + + + Super Game Boy borders + + + + + QGBA::ShaderSelector + + + No shader active + + + + + + Load shader + + + + + No shader loaded + + + + + by %1 + + + + + Preprocessing + + + + + Pass %1 + + + + + Shaders + + + + + Active Shader: + + + + + Name + + + + + Author + + + + + Description + + + + + Unload Shader + + + + + Load New Shader + + + + + QGBA::ShortcutModel + + + Action + + + + + Keyboard + + + + + Gamepad + + + + + QGBA::ShortcutView + + + Edit Shortcuts + + + + + Keyboard + + + + + Gamepad + + + + + Clear + + + + + QGBA::TileView + + + Export tiles + + + + + + Portable Network Graphics (*.png) + + + + + Export tile + + + + + Tiles + + + + + Export Selected + + + + + Export All + + + + + 256 colors + + + + + Palette + + + + + Magnification + + + + + Tiles per row + + + + + Fit to window + + + + + Displayed tiles + + + + + Only BG tiles + + + + + Only OBJ tiles + + + + + Both + + + + + Copy Selected + + + + + Copy All + + + + + QGBA::VideoView + + + Failed to open output video file: %1 + + + + + Native (%0x%1) + + + + + Select output file + + + + + Record Video + + + + + Start + + + + + Stop + + + + + Select File + + + + + Presets + + + + + High &Quality + + + + + &YouTube + + + + + + WebM + + + + + + MP4 + + + + + &Lossless + + + + + 4K + + + + + &1080p + + + + + &720p + + + + + &480p + + + + + &Native + + + + + Format + + + + + MKV + + + + + AVI + + + + + HEVC + + + + + HEVC (NVENC) + + + + + VP8 + + + + + VP9 + + + + + FFV1 + + + + + + None + + + + + FLAC + + + + + WavPack + + + + + Opus + + + + + Vorbis + + + + + MP3 + + + + + AAC + + + + + Uncompressed + + + + + Bitrate (kbps) + + + + + ABR + + + + + H.264 + + + + + H.264 (NVENC) + + + + + VBR + + + + + CRF + + + + + Dimensions + + + + + Lock aspect ratio + + + + + Show advanced + Visa avancerat + + + + QGBA::Window + + + Archives (%1) + + + + + + + Select ROM + + + + + Select folder + + + + + + Select save + + + + + Select patch + + + + + Patches (*.ips *.ups *.bps) + + + + + Select e-Reader dotcode + + + + + e-Reader card (*.raw *.bin *.bmp) + + + + + Select image + + + + + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) + + + + + GameShark saves (*.sps *.xps) + + + + + Select video log + + + + + Video logs (*.mvl) + + + + + Crash + + + + + The game has crashed with the following error: + +%1 + + + + + Couldn't Start + + + + + Could not start game. + + + + + Unimplemented BIOS call + + + + + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. + + + + + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. + + + + + Really make portable? + + + + + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? + + + + + Restart needed + + + + + Some changes will not take effect until the emulator is restarted. + + + + + - Player %1 of %2 + + + + + %1 - %2 + + + + + %1 - %2 - %3 + + + + + %1 - %2 (%3 fps) - %4 + + + + + &File + + + + + Load &ROM... + + + + + Load ROM in archive... + + + + + Add folder to library... + + + + + Save games (%1) + + + + + Select save game + + + + + mGBA save state files (%1) + + + + + + Select save state + + + + + Select e-Reader card images + + + + + Image file (*.png *.jpg *.jpeg) + + + + + Conversion finished + + + + + %1 of %2 e-Reader cards converted successfully. + + + + + Load alternate save game... + + + + + Load temporary save game... + + + + + Load &patch... + + + + + Boot BIOS + + + + + Replace ROM... + + + + + Scan e-Reader dotcodes... + + + + + Convert e-Reader card image to raw... + + + + + ROM &info... + + + + + Recent + + + + + Make portable + + + + + &Load state + + + + + Load state file... + + + + + &Save state + + + + + Save state file... + + + + + Quick load + + + + + Quick save + + + + + Load recent + + + + + Save recent + + + + + Undo load state + + + + + Undo save state + + + + + + State &%1 + + + + + Load camera image... + + + + + Convert save game... + + + + + GameShark saves (*.gsv *.sps *.xps) + + + + + Reset needed + + + + + Some changes will not take effect until the game is reset. + + + + + Save games + + + + + Import GameShark Save... + + + + + Export GameShark Save... + + + + + Automatically determine + + + + + Use player %0 save game + + + + + New multiplayer window + + + + + Connect to Dolphin... + + + + + Report bug... + + + + + About... + + + + + E&xit + + + + + &Emulation + + + + + &Reset + + + + + Sh&utdown + + + + + Yank game pak + + + + + &Pause + + + + + &Next frame + + + + + Fast forward (held) + + + + + &Fast forward + + + + + Fast forward speed + + + + + Unbounded + + + + + %0x + + + + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + + Rewind (held) + + + + + Re&wind + + + + + Step backwards + + + + + Solar sensor + + + + + Increase solar level + + + + + Decrease solar level + + + + + Brightest solar level + + + + + Darkest solar level + + + + + Brightness %1 + + + + + Game Boy Printer... + + + + + BattleChip Gate... + + + + + Audio/&Video + + + + + Frame size + + + + + %1× + + + + + Toggle fullscreen + + + + + Lock aspect ratio + + + + + Force integer scaling + + + + + Interframe blending + + + + + Bilinear filtering + + + + + Frame&skip + + + + + Mute + + + + + FPS target + + + + + Native (59.7275) + + + + + Take &screenshot + + + + + F12 + + + + + Record A/V... + + + + + Record GIF/WebP/APNG... + + + + + Video layers + + + + + Audio channels + + + + + Adjust layer placement... + + + + + &Tools + + + + + View &logs... + + + + + Game &overrides... + + + + + Game Pak sensors... + + + + + &Cheats... + + + + + Create forwarder... + + + + + Settings... + + + + + Open debugger console... + + + + + Start &GDB server... + + + + + Scripting... + + + + + Game state views + + + + + View &palette... + + + + + View &sprites... + + + + + View &tiles... + + + + + View &map... + + + + + &Frame inspector... + + + + + View memory... + + + + + Search memory... + + + + + View &I/O registers... + + + + + Record debug video log... + + + + + Stop debug video log + + + + + Exit fullscreen + + + + + GameShark Button (held) + + + + + Autofire + + + + + Autofire A + + + + + Autofire B + + + + + Autofire L + + + + + Autofire R + + + + + Autofire Start + + + + + Autofire Select + + + + + Autofire Up + + + + + Autofire Right + + + + + Autofire Down + + + + + Autofire Left + + + + + Clear + + + + + QObject + + + %1 byte + + + + + %1 kiB + + + + + %1 MiB + + + + + GBA + + + + + GB + + + + + ? + + + + + Super (L) + + + + + Super (R) + + + + + Menu + + + + + QShortcut + + + Shift + + + + + Control + + + + + Alt + + + + + Meta + + + + diff --git a/src/platform/qt/ts/mgba-template.ts b/src/platform/qt/ts/mgba-template.ts index 6e39742bf..61b57b820 100644 --- a/src/platform/qt/ts/mgba-template.ts +++ b/src/platform/qt/ts/mgba-template.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + + + + + Game Boy ROMs (%1) + + + + + All ROMs (%1) + + + + + %1 Video Logs (*.mvl) + + + QGBA::AboutScreen @@ -86,22 +109,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable - + Development - + Unknown - + (None) @@ -358,48 +381,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 - + Failed to open game file: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 - + Failed to open snapshot file for writing: %1 @@ -407,17 +430,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 - + Could not load game. Are you sure it's in the correct format? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -443,7 +466,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -496,6 +519,200 @@ Download size: %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -534,52 +751,52 @@ Download size: %3 - + Export frame - + Portable Network Graphics (*.png) - + None - + Background - + Window - + Objwin - + Sprite - + Backdrop - + Frame - + %1 %2 @@ -587,7 +804,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence @@ -595,22 +812,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button - + Clear Analog - + Refresh - + Set all @@ -744,148 +961,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2763,26 +3000,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- - - - Super (L) - - - - - Super (R) - - - - - Menu - - QGBA::LibraryTree @@ -2904,7 +3126,7 @@ Download size: %3 - + Slot %1 @@ -3130,39 +3352,39 @@ Download size: %3 - + None - + Both - + Horizontal - + Vertical - - - + + + N/A - + Export map - + Portable Network Graphics (*.png) @@ -3413,22 +3635,22 @@ Download size: %3 - + (%0/%1×) - + (⅟%0×) - + (%0×) - + %1 byte%2 @@ -3519,6 +3741,24 @@ Download size: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4017,6 +4257,7 @@ Download size: %3 + (unknown) @@ -4060,6 +4301,11 @@ Download size: %3 CRC32: + + + Save file: + + QGBA::ReportView @@ -4167,7 +4413,7 @@ Download size: %3 - + Cannot convert save games between platforms @@ -4193,92 +4439,97 @@ Download size: %3 - + %1 %2 save game - + little endian - + big endian - + SRAM - + %1 flash - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 - + unpacked MBC2 - + MBC6 flash - + MBC6 combined SRAM + flash - + MBC6 SRAM - + TAMA5 - + %1 (%2) - + %1 save state with embedded %2 save game - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4286,7 +4537,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4432,102 +4683,112 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia - + SDL - + Software (Qt) - - + + OpenGL - + OpenGL (force version 1.x) - + None - + None (Still Image) - + Keyboard - + Controllers - + Shortcuts - - + + Shaders - + Select BIOS - + Select directory - - (%1×%2) + + Select image - - Never + + Image file (*.png *.jpg *.jpeg) + (%1×%2) + + + + + Never + + + + Just now - + Less than an hour ago - + %n hour(s) ago - + %n day(s) ago @@ -4725,7 +4986,7 @@ Download size: %3 - + frames @@ -4813,77 +5074,77 @@ Download size: %3 - + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now - + Default color palette only - + SGB color palette if available - + GBC color palette if available - + SGB (preferred) or GBC color palette if available - + Game Boy Camera - + Driver: - + Source: @@ -4978,58 +5239,68 @@ Download size: %3 - + + Custom border: + + + + Fast forward speed: - - + + Unbounded - + Fast forward (held) speed: - + Autofire interval: - + Enable rewind - + Rewind history: - + + Rewind speed: + + + + Idle loops: - + Run all - + Remove known - + Detect and remove - + Preload entire ROM into memory @@ -5050,42 +5321,42 @@ Download size: %3 - + Models - + GB only: - + SGB compatible: - + GBC only: - + GBC compatible: - + SGB and GBC compatible: - + Game Boy palette - + Preset: @@ -5102,154 +5373,155 @@ Download size: %3 - + Enable Game Boy Player features by default - + Enable VBA bug compatibility in ROM hacks - + Video renderer: - + Software - + OpenGL enhancements - + High-resolution scale: - + (240×160) - + XQ GBA audio (experimental) - + GB BIOS file: - - - - - - - - - + + + + + + + + + + Browse - + Use BIOS file if found - + Skip BIOS intro - + GBA BIOS file: - + GBC BIOS file: - + SGB BIOS file: - + Save games - - - - - + + + + + Same directory as the ROM - + Save states - + Screenshots - + Patches - + Cheats - + Log to file - + Log to console - + Select Log File - + Default BG colors: - + Default sprite colors 1: - + Default sprite colors 2: - + Super Game Boy borders @@ -5262,27 +5534,28 @@ Download size: %3 - + + Load shader - + No shader loaded - + by %1 - + Preprocessing - + Pass %1 @@ -5325,17 +5598,17 @@ Download size: %3 QGBA::ShortcutModel - + Action - + Keyboard - + Gamepad @@ -5455,17 +5728,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 - + Native (%0x%1) - + Select output file @@ -5676,784 +5949,779 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - - - - - Game Boy ROMs (%1) - - - - - All ROMs (%1) - - - - - %1 Video Logs (*.mvl) - - - - + Archives (%1) - - - + + + Select ROM - + Select folder - - + + Select save - + Select patch - + Patches (*.ips *.ups *.bps) - + Select e-Reader dotcode - + e-Reader card (*.raw *.bin *.bmp) - + Select image - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) - + GameShark saves (*.sps *.xps) - + Select video log - + Video logs (*.mvl) - + Crash - + The game has crashed with the following error: %1 - + Couldn't Start - + Could not start game. - + Unimplemented BIOS call - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. - + Really make portable? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - + Restart needed - + Some changes will not take effect until the emulator is restarted. - + - Player %1 of %2 - + %1 - %2 - + %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File - + Load &ROM... - + Load ROM in archive... - + Add folder to library... - + Save games (%1) - + Select save game - + mGBA save state files (%1) - - + + Select save state - + Select e-Reader card images - + Image file (*.png *.jpg *.jpeg) - + Conversion finished - + %1 of %2 e-Reader cards converted successfully. - + Load alternate save game... - + Load temporary save game... - + Load &patch... - + Boot BIOS - + Replace ROM... - + Scan e-Reader dotcodes... - + Convert e-Reader card image to raw... - + ROM &info... - + Recent - + Make portable - + &Load state - + Load state file... - + &Save state - + Save state file... - + Quick load - + Quick save - + Load recent - + Save recent - + Undo load state - + Undo save state - - + + State &%1 - + Load camera image... - + Convert save game... - + GameShark saves (*.gsv *.sps *.xps) - + Reset needed - + Some changes will not take effect until the game is reset. - + Save games - + Import GameShark Save... - + Export GameShark Save... - + Automatically determine - + Use player %0 save game - + New multiplayer window - + Connect to Dolphin... - + Report bug... - + About... - + E&xit - + &Emulation - + &Reset - + Sh&utdown - + Yank game pak - + &Pause - + &Next frame - + Fast forward (held) - + &Fast forward - + Fast forward speed - + Unbounded - + %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) - + Re&wind - + Step backwards - + Solar sensor - + Increase solar level - + Decrease solar level - + Brightest solar level - + Darkest solar level - + Brightness %1 - + Game Boy Printer... - + BattleChip Gate... - + Audio/&Video - + Frame size - + %1× - + Toggle fullscreen - + Lock aspect ratio - + Force integer scaling - + Interframe blending - + Bilinear filtering - + Frame&skip - + Mute - + FPS target - + Native (59.7275) - + Take &screenshot - + F12 - + Record A/V... - + Record GIF/WebP/APNG... - + Video layers - + Audio channels - + Adjust layer placement... - + &Tools - + View &logs... - + Game &overrides... - + Game Pak sensors... - + &Cheats... - + + Create forwarder... + + + + Settings... - + Open debugger console... - + Start &GDB server... - + Scripting... - + Game state views - + View &palette... - + View &sprites... - + View &tiles... - + View &map... - + &Frame inspector... - + View memory... - + Search memory... - + View &I/O registers... - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear @@ -6461,55 +6729,70 @@ Download size: %3 QObject - + %1 byte - + %1 kiB - + %1 MiB - + GBA - + GB - + ? + + + Super (L) + + + + + Super (R) + + + + + Menu + + QShortcut - + Shift - + Control - + Alt - + Meta diff --git a/src/platform/qt/ts/mgba-tr.ts b/src/platform/qt/ts/mgba-tr.ts index e5f5c6074..d239b59c2 100644 --- a/src/platform/qt/ts/mgba-tr.ts +++ b/src/platform/qt/ts/mgba-tr.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + Game Boy Advance ROMları (%1) + + + + Game Boy ROMs (%1) + Game Boy ROMları (%1) + + + + All ROMs (%1) + Bütün ROMlar (%1) + + + + %1 Video Logs (*.mvl) + + + QGBA::AboutScreen @@ -87,22 +110,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable - + Development - + Unknown Bilinmeyen - + (None) @@ -359,48 +382,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 Kayıt dosyası açılamadı: %1 - + Failed to open game file: %1 Oyun dosyası açılamadı: %1 - + Can't yank pack in unexpected platform! Beklenmedik bir platformda kartı çıkaramazsın! - + Failed to open snapshot file for reading: %1 Anlık görüntü dosyası okuma için açılamadı: %1 - + Failed to open snapshot file for writing: %1 Anlık görüntü dosyası yazma için açılamadı: %1 @@ -408,17 +431,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 Oyun dosyası açılamadı: %1 - + Could not load game. Are you sure it's in the correct format? Oyun yüklenemedi. Doğru formatta olduğundan emin misin? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). @@ -444,7 +467,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing @@ -497,6 +520,200 @@ Download size: %3 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + + + + + Banner + + + + + QGBA::ForwarderGeneratorVita + + + Bubble + + + + + Background + + + + + Startup + + + + + QGBA::ForwarderView + + + Create forwarder + + + + + Files + + + + + ROM file: + + + + + + + Browse + Gözat + + + + Output filename: + + + + + Forwarder base: + + + + + Latest stable version + + + + + Latest development build + + + + + Specific file + + + + + Base file: + + + + + System + + + + + 3DS + + + + + Vita + + + + + Presentation + + + + + Title: + + + + + Images: + + + + + Use default image + + + + + Preferred size: + + + + + Select image file + + + + + Select ROM file + + + + + Select output filename + + + + + Select base file + + + + + Build finished + + + + + Forwarder finished building + + + + + Build failed + + + + + Failed to build forwarder + + + + + %1 installable package (*.%2) + + + + + Select an image + + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -535,52 +752,52 @@ Download size: %3 Sıfırla - + Export frame Kareyi Dışarı Aktar - + Portable Network Graphics (*.png) Portable Network Graphics (*.png) - + None Hiçbiri - + Background Arka Plan - + Window Pencere - + Objwin Nes. Pen. - + Sprite Sprite - + Backdrop Arka fon - + Frame Kare - + %1 %2 %1 %2 @@ -588,7 +805,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence Discord etkinliğini etkinleştir @@ -596,22 +813,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button Tuşu Temizle - + Clear Analog Analogu Temizle - + Refresh Yenile - + Set all Tümüne ayarla @@ -745,148 +962,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect Otomatik tespit - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam - + TAMA5 TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) - + Pokémon Jade/Diamond - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2764,26 +3001,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- - - - Super (L) - Süper (L) - - - - Super (R) - Süper (R) - - - - Menu - Menü - QGBA::LibraryTree @@ -2905,7 +3127,7 @@ Download size: %3 Bozulmuş - + Slot %1 @@ -3131,39 +3353,39 @@ Download size: %3 Ayna - + None Hiçbiri - + Both - + Horizontal Yatay - + Vertical Dikey - - - + + + N/A N/A - + Export map Haritayı dışarı aktar - + Portable Network Graphics (*.png) @@ -3414,22 +3636,22 @@ Download size: %3 Yenile - + (%0/%1×) - + (⅟%0×) - + (%0×) - + %1 byte%2 @@ -3520,6 +3742,24 @@ Download size: %3 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4018,6 +4258,7 @@ Download size: %3 + (unknown) (bilinmeyen) @@ -4061,6 +4302,11 @@ Download size: %3 CRC32: + + + Save file: + + QGBA::ReportView @@ -4168,7 +4414,7 @@ Download size: %3 Geçerli dönüştürme bulunamadı - + Cannot convert save games between platforms Kayıtlı oyunlar platformlar arasında dönüştürülemez @@ -4194,92 +4440,97 @@ Download size: %3 Çıkış dosyası - + %1 %2 save game %1 %2 kayıtlı oyun - + little endian little endian - + big endian big endian - + SRAM SRAM - + %1 flash %1 flash - + %1 EEPROM %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC %1 SRAM + RTC - + %1 SRAM %1 SRAM - + packed MBC2 paketli MBC2 - + unpacked MBC2 paketlenmemiş MBC2 - + MBC6 flash MBC6 flash - + MBC6 combined SRAM + flash MBC6 ile birleştirilmiş SRAM + flash - + MBC6 SRAM MBC6 SRAM - + TAMA5 TAMA5 - + %1 (%2) %1 (%2) - + %1 save state with embedded %2 save game Gömülü %2 kayıtlı oyunla %1 kayıt durumu - + %1 SharkPort %2 save game - + %1 GameShark Advance SP %2 save game @@ -4287,7 +4538,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer @@ -4433,102 +4684,112 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia - + SDL - + Software (Qt) Yazılım - - + + OpenGL OpenGL - + OpenGL (force version 1.x) - + None Hiçbiri - + None (Still Image) - + Keyboard Klavye - + Controllers - + Shortcuts Kısayollar - - + + Shaders Gölgelendiricler - + Select BIOS BIOS seç - + Select directory Yolu seç - + + Select image + Resim seç + + + + Image file (*.png *.jpg *.jpeg) + Görüntü dosyası (*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never - + Just now - + Less than an hour ago - + %n hour(s) ago - + %n day(s) ago @@ -4726,7 +4987,7 @@ Download size: %3 - + frames Kare @@ -4824,112 +5085,122 @@ Download size: %3 - + + Custom border: + + + + Current channel: - + Current version: - + Update channel: - + Available version: - + (Unknown) - + Last checked: - + Automatically check on start - + Check now - + + Rewind speed: + + + + Models Modeller - + GB only: Sadece GB: - + SGB compatible: SGB uyumlu: - + GBC only: Sadece GBC: - + GBC compatible: Uyumlu GBC: - + SGB and GBC compatible: Uyumlu SGB ve GBC: - + Game Boy palette Game Boy paleti - + Default color palette only Sadece varsayılan renk paleti - + SGB color palette if available Mevcutsa SGB renk paketi - + GBC color palette if available Mevcutsa GBC renk paketi - + SGB (preferred) or GBC color palette if available Mevcutsa SGB (tercih edilen) ya da GBC renk paketi - + Game Boy Camera Game Boy Kamera - + Driver: Sürücü: - + Source: Kaynak: @@ -5015,12 +5286,12 @@ Download size: %3 Durum ekstra veriyi yükle: - + Enable VBA bug compatibility in ROM hacks ROM hacklerinde VBA hata uyumluluğunu etkinleştir - + Preset: Ön ayar: @@ -5040,58 +5311,58 @@ Download size: %3 Başlık çubuğunda ROM adı yerine dosya adını göster - + Fast forward speed: Hızlı sarma hızı: - - + + Unbounded Sınırsız - + Fast forward (held) speed: İleri sarma (tutulan) hızı: - + Autofire interval: Otomatik ateşleme aralığı: - + Enable rewind Geri sarmayı etkinleştir - + Rewind history: Geri alma tarihi: - + Idle loops: - + Run all Hepsini çalıştır - + Remove known Bilinenleri kaldır - + Detect and remove Algıla ve kaldır - + Preload entire ROM into memory Tüm ROM'u belleğe önceden yükle @@ -5108,149 +5379,150 @@ Download size: %3 Hile kodları - + Enable Game Boy Player features by default Game Boy Player özelliklerini varsayılan olarak etkinleştir - + Video renderer: Video oluşturucu: - + Software Yazılım - + OpenGL enhancements OpenGL geliştirmeleri - + High-resolution scale: Yüksek kalite ölçeği: - + (240×160) (240×160) - + XQ GBA audio (experimental) XQ GBA ses (deneysel) - + GB BIOS file: GB BIOS dosyası: - - - - - - - - - + + + + + + + + + + Browse Gözat - + Use BIOS file if found Varsa BIOS dosyasını kullan - + Skip BIOS intro BIOS girişini atla - + GBA BIOS file: GBA BIOS dosyası: - + GBC BIOS file: GBC BIOS dosyası: - + SGB BIOS file: SGB BIOS dosyası: - + Save games Oyunları kaydet - - - - - + + + + + Same directory as the ROM ROM ile aynı dizin - + Save states Konum kaydedici - + Screenshots Ekran Görüntüleri - + Patches Yamalar - + Cheats Hileler - + Log to file Dosyaya günlüğünü gir - + Log to console Konsola günlüğünü gir - + Select Log File Günlük Dosyasını Seç - + Default BG colors: - + Super Game Boy borders Super Game Boy sınırları - + Default sprite colors 1: Varsayılan sprite renkleri 1: - + Default sprite colors 2: Varsayılan sprite renkleri 2: @@ -5263,27 +5535,28 @@ Download size: %3 Hiçbir Gölgelendirici aktif değil - + + Load shader Gölgelendirici yükle - + No shader loaded Gölgelendirici yüklenmedi - + by %1 - + Preprocessing İşleniyor - + Pass %1 @@ -5326,17 +5599,17 @@ Download size: %3 QGBA::ShortcutModel - + Action Eylem - + Keyboard Klavye - + Gamepad Oyun Kolu @@ -5456,17 +5729,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 Çıkış video dosyası açılamadı:%1 - + Native (%0x%1) - + Select output file Çıkış dosyasını seç @@ -5677,120 +5950,100 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - Game Boy Advance ROMları (%1) - - - - Game Boy ROMs (%1) - Game Boy ROMları (%1) - - - - All ROMs (%1) - Bütün ROMlar (%1) - - - - %1 Video Logs (*.mvl) - - - - + Archives (%1) Arşivler (%1) - - - + + + Select ROM ROM seç - + Select folder Klasör seç - - + + Select save Kayıt seç - + Select patch Yama seç - + Patches (*.ips *.ups *.bps) Yamalar (*.ips *.ups *.bps) - + Select e-Reader dotcode e-Okuyucu nokta kodunu seç - + e-Reader card (*.raw *.bin *.bmp) e-Okuyucu kart (*.raw *.bin *.bmp) - + Select e-Reader card images e-Okuyucu kartından görüntüleri seç - + Image file (*.png *.jpg *.jpeg) Görüntü dosyası (*.png *.jpg *.jpeg) - + Conversion finished Dönüştürme tamamlandı - + %1 of %2 e-Reader cards converted successfully. %1 / %2 e-Okuyucu kartları dönüştürme tamamlandı. - + Select image Resim seç - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) Resim dosyası (*.png *.gif *.jpg *.jpeg);;All files (*) - + GameShark saves (*.sps *.xps) GameShark kayıtları (*.sps *.xps) - + Select video log Video günlüğü seç - + Video logs (*.mvl) Video günlükleri (*.mvl) - + Crash Çökme - + The game has crashed with the following error: %1 @@ -5799,664 +6052,679 @@ Download size: %3 %1 - + Unimplemented BIOS call Uygulanmamış BIOS girişi - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. Oyun BIOS dosyasına ihtiyacı var. Lütfen en iyi deneyim için resmi BIOS'u kullanın. - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. Uygun görüntü cihazı oluşturma başarısız, yazılım ekranına dönülüyor. Oyunlar özellikle daha büyük ekranlarda yavaş çalışabilir. - + Really make portable? Taşınabilir yapılsın mı? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? Emülatörün yapılandırmasını yürütülebilir dosya ile aynı dizinden yüklemesini sağlar. Devam etmek istiyor musun? - + Restart needed Yeniden başlatma gerekli - + Some changes will not take effect until the emulator is restarted. Bazı değişiklikler emülatör yeniden başlatılıncaya kadar etkili olmaz. - + - Player %1 of %2 - + %1 - %2 - + %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File - + Load &ROM... &ROM yükle... - + Load ROM in archive... ROM'u arşivden yükle ... - + Add folder to library... Kütüphaneye klasör ekle ... - + Save games Oyunları kaydet - + Automatically determine - + Use player %0 save game - + Load &patch... &Patch yükle... - + Boot BIOS BIOS boot et - + Replace ROM... ROM değişti... - - Game state views - - - - - Convert e-Reader card image to raw... - e-Okuyucu kart resimlerini rawa dönüştür... - - - - ROM &info... - ROM &info... - - - - Recent - Son kullanılanlar - - - - Make portable - Portatif yap - - - - &Load state - &Kaydedilmiş konum yükle - - - - Load state file... - Kaydedilmiş konum dosyası yükle... - - - - &Save state - &Konumu kaydet - - - - Save state file... - Konum dosyasını kaydet... - - - - Quick load - Hızlı Yükle - - - - Quick save - Hızlı kaydet - - - - Load recent - En son yükle - - - - Save recent - Hızlı kaydet - - - - Undo load state - Kaydedilen konum yüklemeyi geri al - - - - Undo save state - Konum kaydetmeyi geri al - - - - - State &%1 - Konum &%1 - - - - Load camera image... - Kamera resmini yükle ... - - - - Convert save game... - Kayıtlı oyun dömnüştürülüyor... - - - - GameShark saves (*.gsv *.sps *.xps) - - - - - Reset needed - - - - - Some changes will not take effect until the game is reset. - - - - - New multiplayer window - Yeni çokoyunculu ekranı - - - - Connect to Dolphin... - Dolphin'e Bağlan... - - - - Report bug... - Hata rapor et... - - - - About... - Hakkında... - - - - E&xit - Çıkış - - - - &Emulation - Emülasyon - - - - &Reset - &Reset - - - - Sh&utdown - Kapat - - - - Yank game pak - - - - - &Pause - &Durdur - - - - &Next frame - &Sonraki kare - - - - Fast forward (held) - İleriye sar(basılı tutun) - - - - &Fast forward - &İleriye sar - - - - Fast forward speed - İleriye sarma hızı - - - - Unbounded - - - - - %0x - - - - - Rewind (held) - Geri sar (basılı tutun) - - - - Re&wind - Geri sar - - - - Step backwards - Geriye doğru adım - - - - Solar sensor - - - - - Increase solar level - Solar seviyesini arttır - - - - Decrease solar level - Solar seviyesini düşür - - - - Brightest solar level - En parlak solar seviyesi - - - - Darkest solar level - En karanlık solar seviyesi - - - - Brightness %1 - Parlaklık:%1 - - - - Game Boy Printer... - Game Boy yazıcısı... - - - - BattleChip Gate... - - - - - Audio/&Video - Ses/&Video - - - - Frame size - Çerçeve boyutu - - - - Toggle fullscreen - Tamekranı aç/kapa - - - - Lock aspect ratio - En boy oranını kilitle - - - - Force integer scaling - Tamsayılı ölçeklendirmeyi zorla - - - - Bilinear filtering - Bilinear filtreleme - - - - Frame&skip - Kare atlama - - - - Mute - Sessiz - - - - FPS target - FPS hedefi - - - - Native (59.7275) - - - - - Take &screenshot - Ekran görüntüsü al - - - - F12 - - - - - Video layers - - - - - Audio channels - Ses kanalları - - - - Adjust layer placement... - Katman yerleşimini ayarlayın... - - - - &Tools - &Araçlar - - - - View &logs... - Kayıtları görüntüle... - - - - Game &overrides... - & Oyunun üzerine yazılanlar... - - - - Couldn't Start - Başlatılamadı - - - - Save games (%1) - Kayıtlı oyunlar (%1) - - - - Select save game - Kayıtlı oyun seç - - - - mGBA save state files (%1) - mGBA kayıt durum dosyası (%1) - - - - - Select save state - Kayıt durumu seç - - - - Could not start game. - Oyun başlatılamadı. - - - - Load alternate save game... - Alternatif kayıtlı oyun yükle... - - - - Load temporary save game... - Geçici kayıtlı oyunu yükle... - - - - Scan e-Reader dotcodes... - e-Okuyucu noktakodları tara... - - - - Import GameShark Save... - GameShark kaydını içeri aktar... - - - - Export GameShark Save... - GameShark kaydını dışarı aktar... - - - - %1× - %1× - - - - Interframe blending - Kareler-arası Karıştırma - - - - Record A/V... - A/V Kayıt... - - - - Record GIF/WebP/APNG... - GIF/WebP/APNG Kayıt... - - - - Game Pak sensors... - Oyun Kartuş sensörleri... - - - - &Cheats... - &Hileler... - - - - Settings... - Ayarlar... - - - - Open debugger console... - Hata ayıklayıcı konsolunu aç ... - - - - Start &GDB server... - &GDB sunucusunu başlat... - - - - Scripting... + + Create forwarder... + Game state views + + + + + Convert e-Reader card image to raw... + e-Okuyucu kart resimlerini rawa dönüştür... + + + + ROM &info... + ROM &info... + + + + Recent + Son kullanılanlar + + + + Make portable + Portatif yap + + + + &Load state + &Kaydedilmiş konum yükle + + + + Load state file... + Kaydedilmiş konum dosyası yükle... + + + + &Save state + &Konumu kaydet + + + + Save state file... + Konum dosyasını kaydet... + + + + Quick load + Hızlı Yükle + + + + Quick save + Hızlı kaydet + + + + Load recent + En son yükle + + + + Save recent + Hızlı kaydet + + + + Undo load state + Kaydedilen konum yüklemeyi geri al + + + + Undo save state + Konum kaydetmeyi geri al + + + + + State &%1 + Konum &%1 + + + + Load camera image... + Kamera resmini yükle ... + + + + Convert save game... + Kayıtlı oyun dömnüştürülüyor... + + + + GameShark saves (*.gsv *.sps *.xps) + + + + + Reset needed + + + + + Some changes will not take effect until the game is reset. + + + + + New multiplayer window + Yeni çokoyunculu ekranı + + + + Connect to Dolphin... + Dolphin'e Bağlan... + + + + Report bug... + Hata rapor et... + + + + About... + Hakkında... + + + + E&xit + Çıkış + + + + &Emulation + Emülasyon + + + + &Reset + &Reset + + + + Sh&utdown + Kapat + + + + Yank game pak + + + + + &Pause + &Durdur + + + + &Next frame + &Sonraki kare + + + + Fast forward (held) + İleriye sar(basılı tutun) + + + + &Fast forward + &İleriye sar + + + + Fast forward speed + İleriye sarma hızı + + + + Unbounded + + + + + %0x + + + + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + + Rewind (held) + Geri sar (basılı tutun) + + + + Re&wind + Geri sar + + + + Step backwards + Geriye doğru adım + + + + Solar sensor + + + + + Increase solar level + Solar seviyesini arttır + + + + Decrease solar level + Solar seviyesini düşür + + + + Brightest solar level + En parlak solar seviyesi + + + + Darkest solar level + En karanlık solar seviyesi + + + + Brightness %1 + Parlaklık:%1 + + + + Game Boy Printer... + Game Boy yazıcısı... + + + + BattleChip Gate... + + + + + Audio/&Video + Ses/&Video + + + + Frame size + Çerçeve boyutu + + + + Toggle fullscreen + Tamekranı aç/kapa + + + + Lock aspect ratio + En boy oranını kilitle + + + + Force integer scaling + Tamsayılı ölçeklendirmeyi zorla + + + + Bilinear filtering + Bilinear filtreleme + + + + Frame&skip + Kare atlama + + + + Mute + Sessiz + + + + FPS target + FPS hedefi + + + + Native (59.7275) + + + + + Take &screenshot + Ekran görüntüsü al + + + + F12 + + + + + Video layers + + + + + Audio channels + Ses kanalları + + + + Adjust layer placement... + Katman yerleşimini ayarlayın... + + + + &Tools + &Araçlar + + + + View &logs... + Kayıtları görüntüle... + + + + Game &overrides... + & Oyunun üzerine yazılanlar... + + + + Couldn't Start + Başlatılamadı + + + + Save games (%1) + Kayıtlı oyunlar (%1) + + + + Select save game + Kayıtlı oyun seç + + + + mGBA save state files (%1) + mGBA kayıt durum dosyası (%1) + + + + + Select save state + Kayıt durumu seç + + + + Could not start game. + Oyun başlatılamadı. + + + + Load alternate save game... + Alternatif kayıtlı oyun yükle... + + + + Load temporary save game... + Geçici kayıtlı oyunu yükle... + + + + Scan e-Reader dotcodes... + e-Okuyucu noktakodları tara... + + + + Import GameShark Save... + GameShark kaydını içeri aktar... + + + + Export GameShark Save... + GameShark kaydını dışarı aktar... + + + + %1× + %1× + + + + Interframe blending + Kareler-arası Karıştırma + + + + Record A/V... + A/V Kayıt... + + + + Record GIF/WebP/APNG... + GIF/WebP/APNG Kayıt... + + + + Game Pak sensors... + Oyun Kartuş sensörleri... + + + + &Cheats... + &Hileler... + + + + Settings... + Ayarlar... + + + + Open debugger console... + Hata ayıklayıcı konsolunu aç ... + + + + Start &GDB server... + &GDB sunucusunu başlat... + + + + Scripting... + + + + View &palette... &Renk Paletini gör... - + View &sprites... &Spriteları gör... - + View &tiles... &Desenleri gör... - + View &map... &Haritayı gör - + &Frame inspector... &Kare denetçisi... - + View memory... Hafıza gör... - + Search memory... Hafızada ara... - + View &I/O registers... &I/O kayıtlarını görüntüle - + Record debug video log... Hata ayıklama video günlüğünü kaydet... - + Stop debug video log Hata ayıklama video günlüğünü durdur - + Exit fullscreen Tam ekrandan çık - + GameShark Button (held) GameShark Butonu (basılı tutun) - + Autofire Otomatik basma - + Autofire A Otomatik basma A - + Autofire B Otomatik basma B - + Autofire L Otomatik basma L - + Autofire R Otomatik basma R - + Autofire Start Otomatik basma Start - + Autofire Select Otomatik basma Select - + Autofire Up Otomatik basma Up - + Autofire Right Otomatik basma Right - + Autofire Down Otomatik basma Down - + Autofire Left Otomatik basma Sol - + Clear Temizle @@ -6464,55 +6732,70 @@ Download size: %3 QObject - + %1 byte %1 bayt - + %1 kiB %1 kiB - + %1 MiB %1 MiB - + GBA - + GB - + ? + + + Super (L) + Süper (L) + + + + Super (R) + Süper (R) + + + + Menu + Menü + QShortcut - + Shift Shift - + Control Kontrol - + Alt Alt - + Meta Derece diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 7c73ad9d8..150ad5404 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -1,6 +1,29 @@ + + QGBA + + + Game Boy Advance ROMs (%1) + Game Boy Advance ROM (%1) + + + + Game Boy ROMs (%1) + Game Boy ROM (%1) + + + + All ROMs (%1) + 所有 ROM (%1) + + + + %1 Video Logs (*.mvl) + %1 视频日志 (*.mvl) + + QGBA::AboutScreen @@ -92,22 +115,22 @@ Download size: %3 QGBA::ApplicationUpdater - + Stable 稳定版 - + Development 开发版 - + Unknown 未知 - + (None) (无) @@ -364,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 重置 r%1-%2 %3 - - + + Rewinding not currently enabled 当前未开启倒带 - + Reset the game? 要重置游戏吗? - + Most games will require a reset to load the new save. Do you want to reset now? 大多数游戏需要重置才能加载新的存档。您要立即重启吗? - + Failed to open save file: %1 打开存档失败: %1 - + Failed to open game file: %1 打开游戏文件失败: %1 - + Can't yank pack in unexpected platform! 无法在意外平台上抽出卡带! - + Failed to open snapshot file for reading: %1 读取快照文件失败: %1 - + Failed to open snapshot file for writing: %1 写入快照文件失败: %1 @@ -413,17 +436,17 @@ Download size: %3 QGBA::CoreManager - + Failed to open game file: %1 打开游戏文件失败: %1 - + Could not load game. Are you sure it's in the correct format? 无法载入游戏。请确认游戏格式是否正确? - + Failed to open save file; in-game saves cannot be updated. Please ensure the save directory is writable without additional privileges (e.g. UAC on Windows). 无法打开存档;游戏内存档无法更新。请确保保存目录是可写的,且没有额外权限(例如 Windows 上的 UAC)。 @@ -449,7 +472,7 @@ Download size: %3 QGBA::DebuggerConsoleController - + Could not open CLI history for writing 无法打开用于写入的 CLI 历史 @@ -502,6 +525,200 @@ Download size: %3 无法连接到 Dolphin。 + + QGBA::ForwarderGenerator + + + 3DS + + + + + Vita + + + + + QGBA::ForwarderGenerator3DS + + + Icon + 图标 + + + + Banner + 横幅 + + + + QGBA::ForwarderGeneratorVita + + + Bubble + 气泡 + + + + Background + 背景 + + + + Startup + 启动 + + + + QGBA::ForwarderView + + + Create forwarder + 创建转发器 + + + + Files + 文件 + + + + ROM file: + ROM 文件: + + + + + + Browse + 浏览 + + + + Output filename: + 输出文件名: + + + + Forwarder base: + 转发器基础: + + + + Latest stable version + 最新稳定版本 + + + + Latest development build + 最新开发版本 + + + + Specific file + 指定文件 + + + + Base file: + 基础文件: + + + + System + 系统 + + + + 3DS + + + + + Vita + + + + + Presentation + 介绍 + + + + Title: + 标题: + + + + Images: + 图像: + + + + Use default image + 使用默认图像 + + + + Preferred size: + 首选大小: + + + + Select image file + 选择图像文件 + + + + Select ROM file + 选择 ROM 文件 + + + + Select output filename + 选择输出文件名 + + + + Select base file + 选择基础文件 + + + + Build finished + 已完成构建 + + + + Forwarder finished building + 已完成构建转发器 + + + + Build failed + 构建失败 + + + + Failed to build forwarder + 构建转发器失败 + + + + %1 installable package (*.%2) + %1 可安装数据包 (*.%2) + + + + Select an image + 选择一个图像 + + + + Image files (*.png *.jpg *.bmp) + + + QGBA::FrameView @@ -540,52 +757,52 @@ Download size: %3 重置 - + Export frame 导出框架 - + Portable Network Graphics (*.png) 便携式网络图形 (*.png) - + None - + Background 背景 - + Window 窗口 - + Objwin Objwin - + Sprite 精灵图 - + Backdrop 背幕 - + Frame - + %1 %2 %1 %2 @@ -593,7 +810,7 @@ Download size: %3 QGBA::GBAApp - + Enable Discord Rich Presence 启用 Discord Rich Presence @@ -601,22 +818,22 @@ Download size: %3 QGBA::GBAKeyEditor - + Clear Button 清除按键 - + Clear Analog 清除模拟控制 - + Refresh 刷新 - + Set all 全部设置 @@ -750,148 +967,168 @@ Download size: %3 QGBA::GameBoy - - + + Autodetect 自动检测 - + Game Boy (DMG) - + Game Boy Pocket (MGB) - + Super Game Boy (SGB) - + Super Game Boy 2 (SGB) - + Game Boy Color (CGB) - + Game Boy Advance (AGB) - + Super Game Boy Color (SGB + CGB) - + ROM Only 仅 ROM - + MBC1 - + MBC2 - + MBC3 - + MBC3 + RTC - + MBC5 - + MBC5 + Rumble MB5 + 震动 - + MBC6 - + MBC7 (Tilt) - + MMM01 - + HuC-1 - + HuC-3 - + Pocket Cam 口袋摄像机 - + TAMA5 - + Wisdom Tree - + + NT (old 1) + + + + + NT (old 2) + + + + NT (new) NT(新) - + Pokémon Jade/Diamond 宝可梦翡翠/钻石 - + BBD - + Hitek - + + GGB-81 + + + + + Li Cheng + + + + Sachen (MMC1) - + Sachen (MMC2) @@ -2769,26 +3006,11 @@ Download size: %3 QGBA::KeyEditor - - + + --- --- - - - Super (L) - Super(L) - - - - Super (R) - Super(R) - - - - Menu - 菜单 - QGBA::LibraryTree @@ -2910,7 +3132,7 @@ Download size: %3 已损坏 - + Slot %1 插槽 %1 @@ -3136,39 +3358,39 @@ Download size: %3 镜像 - + None - + Both 两者 - + Horizontal 水平 - + Vertical 垂直 - - - + + + N/A - + Export map 导出映射 - + Portable Network Graphics (*.png) 便携式网络图形 (*.png) @@ -3419,22 +3641,22 @@ Download size: %3 刷新 - + (%0/%1×) (%0/%1×) - + (⅟%0×) (⅟%0×) - + (%0×) (%0×) - + %1 byte%2 %1 字节%2 @@ -3525,6 +3747,24 @@ Download size: %3 帧 %1 + + QGBA::MultiplayerController + + + Trying to detach a multiplayer player that's not attached + + + + + Trying to get player ID for a multiplayer player that's not attached + + + + + Trying to get save ID for a multiplayer player that's not attached + + + QGBA::ObjView @@ -4023,6 +4263,7 @@ Download size: %3 + (unknown) (未知) @@ -4066,6 +4307,11 @@ Download size: %3 CRC32: CRC32: + + + Save file: + + QGBA::ReportView @@ -4173,7 +4419,7 @@ Download size: %3 未发现有效转换 - + Cannot convert save games between platforms 无法在平台之间转换保存游戏 @@ -4199,92 +4445,97 @@ Download size: %3 输出文件 - + %1 %2 save game %1 %2 保存游戏 - + little endian 小端 - + big endian 大端 - + SRAM - + %1 flash %1 闪存 - + %1 EEPROM - + + + RTC + + + + %1 SRAM + RTC - + %1 SRAM - + packed MBC2 包装的 MBC2 - + unpacked MBC2 未包装的 MBC2 - + MBC6 flash MBC6 闪存 - + MBC6 combined SRAM + flash MBC6组合SRAM+闪存 - + MBC6 SRAM MBC6 SRAM - + TAMA5 - + %1 (%2) %1(%2) - + %1 save state with embedded %2 save game 带嵌入的 %2 保存游戏的 %1 保存状态 - + %1 SharkPort %2 save game %1 SharkPort %2 存档 - + %1 GameShark Advance SP %2 save game %1 GameShark Advance SP %2 存档 @@ -4292,7 +4543,7 @@ Download size: %3 QGBA::ScriptingTextBuffer - + Untitled buffer 无标题缓存 @@ -4438,102 +4689,112 @@ Download size: %3 QGBA::SettingsView - - + + Qt Multimedia Qt Multimedia - + SDL SDL - + Software (Qt) 软件渲染 (Qt) - - + + OpenGL OpenGL - + OpenGL (force version 1.x) OpenGL (强制版本 1.x) - + None - + None (Still Image) 无 (静止图像) - + Keyboard 键盘 - + Controllers 控制器 - + Shortcuts 快捷键 - - + + Shaders 着色器 - + Select BIOS 选择 BIOS - + Select directory 选择目录 - + + Select image + 选择图片 + + + + Image file (*.png *.jpg *.jpeg) + 图像文件(*.png *.jpg *.jpeg) + + + (%1×%2) (%1×%2) - + Never 从不 - + Just now 刚刚 - + Less than an hour ago 不到一小时前 - + %n hour(s) ago %n 小时前 - + %n day(s) ago %n 天前 @@ -4731,7 +4992,7 @@ Download size: %3 - + frames @@ -4819,77 +5080,77 @@ Download size: %3 最小化时: - + Current channel: 当前通道: - + Current version: 当前版本: - + Update channel: 更新通道: - + Available version: 可用版本: - + (Unknown) (未知) - + Last checked: 上次检查更新时间: - + Automatically check on start 启动时自动检查 - + Check now 立即检查更新 - + Default color palette only 只使用默认调色板 - + SGB color palette if available 可用时使用 SGB 调色板 - + GBC color palette if available 可用时使用 GBC 调色板 - + SGB (preferred) or GBC color palette if available 可用时使用 SGB(首选)或 GBC 调色板 - + Game Boy Camera Game Boy Camera - + Driver: 驱动: - + Source: 来源: @@ -4984,58 +5245,68 @@ Download size: %3 重置时显示模拟信息 - + + Custom border: + + + + Fast forward speed: 快进速度: - - + + Unbounded 不限制 - + Fast forward (held) speed: 快进 (按住) 速度: - + Autofire interval: 连发间隔: - + Enable rewind 启用倒带 - + Rewind history: 倒带历史: - + + Rewind speed: + + + + Idle loops: 空循环: - + Run all 全部运行 - + Remove known 移除已知 - + Detect and remove 检测并移除 - + Preload entire ROM into memory 将整个 ROM 预载到内存中 @@ -5056,42 +5327,42 @@ Download size: %3 载入存档附加数据: - + Models 型号 - + GB only: 仅 GB: - + SGB compatible: 兼容 SGB: - + GBC only: 仅 GBC: - + GBC compatible: 兼容 GBC: - + SGB and GBC compatible: 兼容 SGB 和 GBC: - + Game Boy palette Game Boy 调色板 - + Preset: 预设: @@ -5108,154 +5379,155 @@ Download size: %3 作弊码 - + Enable Game Boy Player features by default 默认启用 Game Boy Player 功能 - + Enable VBA bug compatibility in ROM hacks 启用用于改版的 VBA 漏洞兼容模式 - + Video renderer: 视频渲染器: - + Software 软件 - + OpenGL enhancements OpenGL 增强 - + High-resolution scale: 高分辨率比例: - + (240×160) (240×160) - + XQ GBA audio (experimental) XQ GBA 音频 (实验性) - + GB BIOS file: GB BIOS 文件: - - - - - - - - - + + + + + + + + + + Browse 浏览 - + Use BIOS file if found 当可用时使用 BIOS 文件 - + Skip BIOS intro 跳过 BIOS 启动画面 - + GBA BIOS file: GBA BIOS 文件: - + GBC BIOS file: GBC BIOS 文件: - + SGB BIOS file: SGB BIOS 文件: - + Save games 游戏存档 - - - - - + + + + + Same directory as the ROM 与 ROM 所在目录相同 - + Save states 即时存档 - + Screenshots 截图 - + Patches 补丁 - + Cheats 作弊码 - + Log to file 记录日志到文件 - + Log to console 记录日志到控制台 - + Select Log File 选择日志文件 - + Default BG colors: 默认背景色: - + Default sprite colors 1: 默认精灵图颜色 1: - + Default sprite colors 2: 默认精灵图颜色 2: - + Super Game Boy borders Super Game Boy 边框 @@ -5268,27 +5540,28 @@ Download size: %3 无激活的着色器 - + + Load shader 载入着色器 - + No shader loaded 不载入着色器 - + by %1 由 %1 - + Preprocessing - 正在预处理 + 预处理 - + Pass %1 通道 %1 @@ -5331,17 +5604,17 @@ Download size: %3 QGBA::ShortcutModel - + Action 动作 - + Keyboard 键盘 - + Gamepad 游戏手柄 @@ -5461,17 +5734,17 @@ Download size: %3 QGBA::VideoView - + Failed to open output video file: %1 打开输出视频文件失败: %1 - + Native (%0x%1) 原生 (%0x%1) - + Select output file 选择输出文件 @@ -5682,100 +5955,80 @@ Download size: %3 QGBA::Window - - Game Boy Advance ROMs (%1) - Game Boy Advance ROM (%1) - - - - Game Boy ROMs (%1) - Game Boy ROM (%1) - - - - All ROMs (%1) - 所有 ROM (%1) - - - - %1 Video Logs (*.mvl) - %1 视频日志 (*.mvl) - - - + Archives (%1) 压缩文件 (%1) - - - + + + Select ROM 选择 ROM - + Select folder 选择文件夹 - - + + Select save 选择存档 - + Select patch 选择补丁 - + Patches (*.ips *.ups *.bps) 补丁 (*.ips *.ups *.bps) - + Select e-Reader dotcode 选择 e-Reader 点码 - + e-Reader card (*.raw *.bin *.bmp) e-Reader 卡 (*.raw *.bin *.bmp) - + Select image 选择图片 - + Image file (*.png *.gif *.jpg *.jpeg);;All files (*) 图像文件 (*.png *.gif *.jpg *.jpeg);;所有文件 (*) - + GameShark saves (*.sps *.xps) GameShark 存档 (*.sps *.xps) - + Select video log 选择视频日志 - + Video logs (*.mvl) 视频日志文件 (*.mvl) - + Crash 崩溃 - + The game has crashed with the following error: %1 @@ -5784,684 +6037,699 @@ Download size: %3 %1 - + Couldn't Start 无法启动 - + Could not start game. 无法启动游戏。 - + Unimplemented BIOS call 未实现的 BIOS 调用 - + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. 此游戏使用尚未实现的 BIOS 调用。请使用官方 BIOS 以获得最佳体验。 - + Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. 无法创建适合的显示设备,正在回滚到软件显示。游戏的运行速度(特别在大窗口的情况下)可能会变慢。 - + Really make portable? 确定进行程序便携化? - + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? 进行此操作后,模拟器将从其可执行文件所在目录中载入模拟器配置。您想继续吗? - + Restart needed 需要重新启动 - + Some changes will not take effect until the emulator is restarted. 更改将在模拟器下次重新启动时生效。 - + - Player %1 of %2 - 玩家 %1 共 %2 - + %1 - %2 %1 - %2 - + %1 - %2 - %3 %1 - %2 - %3 - + %1 - %2 (%3 fps) - %4 - + &File 文件(&F) - + Load &ROM... 载入 ROM(&R)... - + Load ROM in archive... 从压缩文件中载入 ROM... - + Add folder to library... 将文件夹添加到库中... - + Save games (%1) 保存游戏(%1) - + Select save game 选择保存游戏 - + mGBA save state files (%1) mGBA 即时存档文件(%1) - - + + Select save state 选择即时存档 - + Select e-Reader card images 选择 e-Reader 卡片图像 - + Image file (*.png *.jpg *.jpeg) 图像文件(*.png *.jpg *.jpeg) - + Conversion finished 转换完成 - + %1 of %2 e-Reader cards converted successfully. 成功转换了 %1 张(共 %2 张)e-Reader 卡片。 - + Load alternate save game... 加载备用保存游戏... - + Load temporary save game... 加载临时保存游戏... - + Load &patch... 载入补丁(&P)... - + Boot BIOS 引导 BIOS - + Replace ROM... 替换 ROM... - + Scan e-Reader dotcodes... 扫描 e-Reader 点码... - + Convert e-Reader card image to raw... 将 e-Reader 卡片图像转换为原始数据... - + ROM &info... ROM 信息(&I)... - + Recent 最近打开 - + Make portable 程序便携化 - + &Load state 载入即时存档(&L) - + Load state file... 载入即时存档文件... - + &Save state 保存即时存档(&S) - + Save state file... 保存即时存档文件... - + Quick load 快速读档 - + Quick save 快速存档 - + Load recent 载入最近存档 - + Save recent 保存最近存档 - + Undo load state 撤消读档 - + Undo save state 撤消存档 - - + + State &%1 即时存档 (&%1) - + Load camera image... 载入相机图片... - + Convert save game... 转换保存游戏... - + GameShark saves (*.gsv *.sps *.xps) GameShark 存档 (*.gsv *.sps *.xps) - + Reset needed 需要重启 - + Some changes will not take effect until the game is reset. 某些改动需要重新启动才会生效。 - + Save games 游戏存档 - + Import GameShark Save... 导入 GameShark 存档... - + Export GameShark Save... 导出 GameShark 存档... - + Automatically determine 自动终止 - + Use player %0 save game 使用玩家 %0 存档 - + New multiplayer window 新建多人游戏窗口 - + Connect to Dolphin... 连接到 Dolphin... - + Report bug... 报告错误... - + About... 关于... - + E&xit 退出(&X) - + &Emulation 模拟(&E) - + &Reset 重置(&R) - + Sh&utdown 关机(&U) - + Yank game pak 快速抽出游戏卡带 - + &Pause 暂停(&P) - + &Next frame 下一帧(&N) - + Fast forward (held) 快进 (长按) - + &Fast forward 快进(&F) - + Fast forward speed 快进速度 - + Unbounded 不限制 - + %0x %0x - + + Increase fast forward speed + + + + + Decrease fast forward speed + + + + Rewind (held) 倒带 (长按) - + Re&wind 倒带(&W) - + Step backwards 步退 - + Solar sensor 太阳光传感器 - + Increase solar level 增加太阳光等级 - + Decrease solar level 降低太阳光等级 - + Brightest solar level 太阳光等级为最亮 - + Darkest solar level 太阳光等级为最暗 - + Brightness %1 亮度 %1 - + Game Boy Printer... Game Boy 打印机... - + BattleChip Gate... BattleChip Gate... - + Audio/&Video 音频/视频(&V) - + Frame size 画面大小 - + %1× %1× - + Toggle fullscreen 切换全屏 - + Lock aspect ratio 锁定纵横比 - + Force integer scaling 强制整数缩放 - + Interframe blending 帧间混合 - + Bilinear filtering 双线性过滤 - + Frame&skip 跳帧(&S) - + Mute 静音 - + FPS target 目标 FPS - + Native (59.7275) 原生 (59.7275) - + Take &screenshot 截图(&S) - + F12 F12 - + Record A/V... 录制音频/视频... - + Record GIF/WebP/APNG... 录制 GIF/WebP/APNG... - + Video layers 视频图层 - + Audio channels 音频声道 - + Adjust layer placement... 调整图层布局... - + &Tools 工具(&T) - + View &logs... 查看日志(&L)... - + Game &overrides... 覆写游戏(&O)... - + Game Pak sensors... 游戏卡带传感器... - + &Cheats... 作弊码(&C)... - + + Create forwarder... + 创建转发器... + + + Settings... 设置... - + Open debugger console... 打开调试器控制台... - + Start &GDB server... 打开 GDB 服务器(&G)... - + Scripting... 脚本... - + Game state views 游戏状态视图 - + View &palette... 查看调色板(&P)... - + View &sprites... 查看精灵图(&S)... - + View &tiles... 查看图块(&T)... - + View &map... 查看映射(&M)... - + &Frame inspector... 帧检查器(&F)... - + View memory... 查看内存... - + Search memory... 搜索内存... - + View &I/O registers... 查看 I/O 寄存器(&I)... - + Record debug video log... 记录调试视频日志... - + Stop debug video log 停止记录调试视频日志 - + Exit fullscreen 退出全屏 - + GameShark Button (held) GameShark 键 (长按) - + Autofire 连发 - + Autofire A 连发 A - + Autofire B 连发 B - + Autofire L 连发 L - + Autofire R 连发 R - + Autofire Start 连发 Start - + Autofire Select 连发 Select - + Autofire Up 连发 上 - + Autofire Right 连发 右 - + Autofire Down 连发 下 - + Autofire Left 连发 左 - + Clear 清除 @@ -6469,55 +6737,70 @@ Download size: %3 QObject - + %1 byte %1字节 - + %1 kiB - + %1 MiB %1 兆字节 - + GBA GBA - + GB GB - + ? ? + + + Super (L) + Super(L) + + + + Super (R) + Super(R) + + + + Menu + 菜单 + QShortcut - + Shift Shift - + Control Control - + Alt Alt - + Meta Meta diff --git a/src/platform/qt/utils.cpp b/src/platform/qt/utils.cpp index d6da29781..c445c41b8 100644 --- a/src/platform/qt/utils.cpp +++ b/src/platform/qt/utils.cpp @@ -6,6 +6,7 @@ #include "utils.h" #include +#include #include #include "VFileDevice.h" @@ -64,28 +65,36 @@ bool convertAddress(const QHostAddress* input, Address* output) { return true; } -QString romFilters(bool includeMvl) { +QString romFilters(bool includeMvl, mPlatform platform, bool rawOnly) { QStringList filters; QStringList formats; #ifdef M_CORE_GBA QStringList gbaFormats{ "*.gba", -#if defined(USE_LIBZIP) || defined(USE_MINIZIP) - "*.zip", -#endif -#ifdef USE_LZMA - "*.7z", -#endif -#ifdef USE_ELF - "*.elf", -#endif "*.agb", "*.mb", "*.rom", "*.bin"}; - formats.append(gbaFormats); - filters.append(QCoreApplication::translate("QGBA", "Game Boy Advance ROMs (%1)", nullptr).arg(gbaFormats.join(QChar(' ')))); + if (!rawOnly) { + gbaFormats += QStringList{ +#if defined(USE_LIBZIP) || defined(USE_MINIZIP) + "*.zip", +#endif +#ifdef USE_LZMA + "*.7z", +#endif +#ifdef USE_ELF + "*.elf", +#endif + }; + } + if (platform == mPLATFORM_NONE || platform == mPLATFORM_GBA) { + formats.append(gbaFormats); + } + if (platform == mPLATFORM_NONE) { + filters.append(QCoreApplication::translate("QGBA", "Game Boy Advance ROMs (%1)", nullptr).arg(gbaFormats.join(QChar(' ')))); + } #endif #ifdef M_CORE_GB @@ -93,16 +102,25 @@ QString romFilters(bool includeMvl) { "*.gb", "*.gbc", "*.sgb", -#if defined(USE_LIBZIP) || defined(USE_MINIZIP) - "*.zip", -#endif -#ifdef USE_LZMA - "*.7z", -#endif "*.rom", "*.bin"}; - formats.append(gbFormats); - filters.append(QCoreApplication::translate("QGBA", "Game Boy ROMs (%1)", nullptr).arg(gbFormats.join(QChar(' ')))); + + if (!rawOnly) { + gbFormats += QStringList{ +#if defined(USE_LIBZIP) || defined(USE_MINIZIP) + "*.zip", +#endif +#ifdef USE_LZMA + "*.7z", +#endif + }; + } + if (platform == mPLATFORM_NONE || platform == mPLATFORM_GBA) { + formats.append(gbFormats); + } + if (platform == mPLATFORM_NONE) { + filters.append(QCoreApplication::translate("QGBA", "Game Boy ROMs (%1)", nullptr).arg(gbFormats.join(QChar(' ')))); + } #endif formats.removeDuplicates(); @@ -120,7 +138,14 @@ bool extractMatchingFile(VDir* dir, std::function filter) continue; } VFile* outfile = VFileOpen(target.toUtf8().constData(), O_WRONLY | O_TRUNC | O_CREAT); + if (!outfile) { + return false; + } VFile* infile = dir->openFile(dir, entry->name(entry), O_RDONLY); + if (!infile) { + outfile->close(outfile); + return false; + } VFileDevice::copyFile(infile, outfile); infile->close(infile); outfile->close(outfile); @@ -129,4 +154,27 @@ bool extractMatchingFile(VDir* dir, std::function filter) return false; } +QString keyName(int key) { + switch (key) { +#ifndef Q_OS_MAC + case Qt::Key_Shift: + return QCoreApplication::translate("QShortcut", "Shift"); + case Qt::Key_Control: + return QCoreApplication::translate("QShortcut", "Control"); + case Qt::Key_Alt: + return QCoreApplication::translate("QShortcut", "Alt"); + case Qt::Key_Meta: + return QCoreApplication::translate("QShortcut", "Meta"); +#endif + case Qt::Key_Super_L: + return QObject::tr("Super (L)"); + case Qt::Key_Super_R: + return QObject::tr("Super (R)"); + case Qt::Key_Menu: + return QObject::tr("Menu"); + default: + return QKeySequence(key).toString(QKeySequence::NativeText); + } +} + } diff --git a/src/platform/qt/utils.h b/src/platform/qt/utils.h index 72ce74c30..cad2595b5 100644 --- a/src/platform/qt/utils.h +++ b/src/platform/qt/utils.h @@ -72,7 +72,49 @@ constexpr const T& clamp(const T& v, const T& lo, const T& hi) { } #endif -QString romFilters(bool includeMvl = false); +template +constexpr T saturateCast(U value) { + if (std::numeric_limits::is_signed == std::numeric_limits::is_signed) { + if (value > std::numeric_limits::max()) { + return std::numeric_limits::max(); + } + if (value < std::numeric_limits::min()) { + return std::numeric_limits::min(); + } + } else if (std::numeric_limits::is_signed) { + if (value > static_cast(std::numeric_limits::max())) { + std::numeric_limits::max(); + } + } else { + if (value < 0) { + return 0; + } + if (static_cast(value) > std::numeric_limits::max()) { + std::numeric_limits::max(); + } + } + return static_cast(value); +} + +template<> +constexpr unsigned saturateCast(int value) { + if (value < 0) { + return 0; + } + return static_cast(value); +} + +template<> +constexpr int saturateCast(unsigned value) { + if (value > static_cast(std::numeric_limits::max())) { + return std::numeric_limits::max(); + } + return static_cast(value); +} + +QString romFilters(bool includeMvl = false, mPlatform platform = mPLATFORM_NONE, bool rawOnly = false); bool extractMatchingFile(VDir* dir, std::function filter); +QString keyName(int key); + } diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index cacf0bc48..ca1919da9 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -22,6 +22,9 @@ if (SDL_VERSION EQUAL "2") endif() endif() + if(APPLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.7") + endif() set(SDLMAIN_LIBRARY ${SDL2MAIN_LIBRARY}) endif() endif() @@ -67,20 +70,20 @@ endif() set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libsdl${SDL_VERSION_DEBIAN}" PARENT_SCOPE) -file(GLOB PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sdl-*.c) +file(GLOB PLATFORM_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sdl-*.c) set(PLATFORM_LIBRARY ${SDL_LIBRARY} ${SDLMAIN_LIBRARY} ${SDL_LIBRARY} ${PIXMAN-1_LIBRARIES}) -include_directories(${CMAKE_SOURCE_DIR}/src/platform/sdl ${PIXMAN-1_INCLUDE_DIRS} ${SDL_INCLUDE_DIR}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${PIXMAN-1_INCLUDE_DIRS} ${SDL_INCLUDE_DIR}) set(SDL_INCLUDE_DIR "${SDL_INCLUDE_DIR}" PARENT_SCOPE) set(SDL_LIBRARY "${SDL_LIBRARY}" PARENT_SCOPE) set(SDLMAIN_LIBRARY "${SDLMAIN_LIBRARY}" PARENT_SCOPE) -set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/main.c) +set(MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/main.c) if(BUILD_RASPI) add_definitions(-DBUILD_RASPI) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/rpi-common.c) - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c) + list(APPEND PLATFORM_SRC ${PROJECT_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_CURRENT_SOURCE_DIR}/gl-common.c ${CMAKE_CURRENT_SOURCE_DIR}/rpi-common.c) + list(APPEND MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gles2-sdl.c) set(OPENGLES2_LIBRARY "-lEGL -lGLESv2 -lbcm_host") set(BUILD_GLES2 ON CACHE BOOL "Using OpenGL|ES 2" FORCE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fgnu89-inline") @@ -92,21 +95,21 @@ if(BUILD_RASPI) endif() if(BUILD_PANDORA) - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/pandora-sdl.c) + list(APPEND MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/pandora-sdl.c) else() if(BUILD_GL) - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) + list(APPEND MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gl-sdl.c) + list(APPEND PLATFORM_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gl-common.c) endif() if(BUILD_GLES2) - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c) - list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) + list(APPEND MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gles2-sdl.c) + list(APPEND PLATFORM_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gl-common.c) include_directories(${OPENGLES2_INCLUDE_DIR}) endif() if(SDL_VERSION EQUAL "2") - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl2.c) + list(APPEND MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sw-sdl2.c) else() - list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl1.c) + list(APPEND MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/sw-sdl1.c) endif() endif() @@ -126,7 +129,7 @@ else() endif() install(TARGETS ${BINARY_NAME}-sdl DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-sdl) if(UNIX) - install(FILES ${CMAKE_SOURCE_DIR}/doc/mgba.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-sdl) + install(FILES ${PROJECT_SOURCE_DIR}/doc/mgba.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-sdl) endif() if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") diff --git a/src/platform/sdl/gl-common.c b/src/platform/sdl/gl-common.c index f0073a904..1ce9100e8 100644 --- a/src/platform/sdl/gl-common.c +++ b/src/platform/sdl/gl-common.c @@ -5,10 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "main.h" +#include +#include #include +#ifdef USE_PNG +#include +#include +#endif + void mSDLGLDoViewport(int w, int h, struct VideoBackend* v) { - v->resized(v, w, h); + v->contextResized(v, w, h); v->clear(v); v->swap(v); v->clear(v); @@ -24,6 +31,60 @@ void mSDLGLCommonSwap(struct VideoBackend* context) { #endif } +bool mSDLGLCommonLoadBackground(struct VideoBackend* context) { +#ifdef USE_PNG + struct mSDLRenderer* renderer = context->user; + const char* bgImage = mCoreConfigGetValue(&renderer->core->config, "backgroundImage"); + if (!bgImage) { + return false; + } + struct VFile* vf = VFileOpen(bgImage, O_RDONLY); + if (!vf) { + return false; + } + + bool ok = false; + png_structp png = PNGReadOpen(vf, 0); + png_infop info = png_create_info_struct(png); + png_infop end = png_create_info_struct(png); + if (!png || !info || !end) { + goto done; + } + + if (!PNGReadHeader(png, info)) { + goto done; + } + unsigned width = png_get_image_width(png, info); + unsigned height = png_get_image_height(png, info); + uint32_t* pixels = malloc(width * height * 4); + if (!pixels) { + goto done; + } + + if (!PNGReadPixels(png, info, pixels, width, height, width) || !PNGReadFooter(png, end)) { + free(pixels); + goto done; + } + + struct mRectangle dims = { + .width = width, + .height = height + }; + context->setLayerDimensions(context, VIDEO_LAYER_BACKGROUND, &dims); + context->setImage(context, VIDEO_LAYER_BACKGROUND, pixels); + free(pixels); + ok = true; + +done: + PNGReadClose(png, info, end); + vf->close(vf); + return ok; +#else + UNUSED(context); + return false; +#endif +} + bool mSDLGLCommonInit(struct mSDLRenderer* renderer) { #ifndef COLOR_16_BIT SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); @@ -66,3 +127,54 @@ bool mSDLGLCommonInit(struct mSDLRenderer* renderer) { #endif return true; } + +void mSDLGLCommonRunloop(struct mSDLRenderer* renderer, void* user) { + struct mCoreThread* context = user; + SDL_Event event; + struct VideoBackend* v = renderer->backend; + + if (mSDLGLCommonLoadBackground(v)) { + renderer->player.windowUpdated = true; + VideoBackendRecenter(v, 1); +#if SDL_VERSION_ATLEAST(2, 0, 0) + int width, height; + v->imageSize(v, VIDEO_LAYER_IMAGE, &width, &height); + SDL_SetWindowSize(renderer->window, width * renderer->ratio, height * renderer->ratio); +#endif + } + + while (mCoreThreadIsActive(context)) { + while (SDL_PollEvent(&event)) { + mSDLHandleEvent(context, &renderer->player, &event); + // Event handling can change the size of the screen + if (renderer->player.windowUpdated) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); +#else + renderer->viewportWidth = renderer->player.newWidth; + renderer->viewportHeight = renderer->player.newHeight; + mSDLGLCommonInit(renderer); +#endif + mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, v); + renderer->player.windowUpdated = 0; + } + } + renderer->core->currentVideoSize(renderer->core, &renderer->width, &renderer->height); + struct mRectangle dims; + v->layerDimensions(v, VIDEO_LAYER_IMAGE, &dims); + if (dims.width < 0 || dims.height < 0 || renderer->width != (unsigned) dims.width || renderer->height != (unsigned) dims.height) { + renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width); + dims.width = renderer->width; + dims.height = renderer->height; + v->setLayerDimensions(v, VIDEO_LAYER_IMAGE, &dims); + VideoBackendRecenter(v, 1); + } + + if (mCoreSyncWaitFrameStart(&context->impl->sync)) { + v->setImage(v, VIDEO_LAYER_IMAGE, renderer->outputBuffer); + } + mCoreSyncWaitFrameEnd(&context->impl->sync); + v->drawFrame(v); + v->swap(v); + } +} diff --git a/src/platform/sdl/gl-common.h b/src/platform/sdl/gl-common.h index be98d7964..f52cfd633 100644 --- a/src/platform/sdl/gl-common.h +++ b/src/platform/sdl/gl-common.h @@ -15,6 +15,8 @@ struct mSDLRenderer; void mSDLGLDoViewport(int w, int h, struct VideoBackend* v); void mSDLGLCommonSwap(struct VideoBackend* context); bool mSDLGLCommonInit(struct mSDLRenderer* renderer); +void mSDLGLCommonRunloop(struct mSDLRenderer* renderer, void* user); +bool mSDLGLCommonLoadBackground(struct VideoBackend* context); CXX_GUARD_END diff --git a/src/platform/sdl/gl-sdl.c b/src/platform/sdl/gl-sdl.c index 6c1508d33..139d5a36e 100644 --- a/src/platform/sdl/gl-sdl.c +++ b/src/platform/sdl/gl-sdl.c @@ -8,19 +8,17 @@ #include "gl-common.h" #include -#include -#include #include "platform/opengl/gl.h" static bool mSDLGLInit(struct mSDLRenderer* renderer); -static void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user); static void mSDLGLDeinit(struct mSDLRenderer* renderer); void mSDLGLCreate(struct mSDLRenderer* renderer) { renderer->init = mSDLGLInit; renderer->deinit = mSDLGLDeinit; - renderer->runloop = mSDLGLRunloop; + renderer->runloop = mSDLGLCommonRunloop; + renderer->backend = &renderer->gl.d; } bool mSDLGLInit(struct mSDLRenderer* renderer) { @@ -37,48 +35,18 @@ bool mSDLGLInit(struct mSDLRenderer* renderer) { renderer->gl.d.filter = renderer->filter; renderer->gl.d.swap = mSDLGLCommonSwap; renderer->gl.d.init(&renderer->gl.d, 0); - renderer->gl.d.setDimensions(&renderer->gl.d, renderer->width, renderer->height); + struct mRectangle dims = { + .x = 0, + .y = 0, + .width = renderer->width, + .height = renderer->height + }; + renderer->gl.d.setLayerDimensions(&renderer->gl.d, VIDEO_LAYER_IMAGE, &dims); mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); return true; } -void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) { - struct mCoreThread* context = user; - SDL_Event event; - struct VideoBackend* v = &renderer->gl.d; - - while (mCoreThreadIsActive(context)) { - while (SDL_PollEvent(&event)) { - mSDLHandleEvent(context, &renderer->player, &event); - // Event handling can change the size of the screen - if (renderer->player.windowUpdated) { -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); -#else - renderer->viewportWidth = renderer->player.newWidth; - renderer->viewportHeight = renderer->player.newHeight; - mSDLGLCommonInit(renderer); -#endif - mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, v); - renderer->player.windowUpdated = 0; - } - } - renderer->core->desiredVideoDimensions(renderer->core, &renderer->width, &renderer->height); - if (renderer->width != v->width || renderer->height != v->height) { - renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width); - v->setDimensions(v, renderer->width, renderer->height); - } - - if (mCoreSyncWaitFrameStart(&context->impl->sync)) { - v->postFrame(v, renderer->outputBuffer); - } - mCoreSyncWaitFrameEnd(&context->impl->sync); - v->drawFrame(v); - v->swap(v); - } -} - void mSDLGLDeinit(struct mSDLRenderer* renderer) { if (renderer->gl.d.deinit) { renderer->gl.d.deinit(&renderer->gl.d); diff --git a/src/platform/sdl/gles2-sdl.c b/src/platform/sdl/gles2-sdl.c index 7237b6273..9bae33b95 100644 --- a/src/platform/sdl/gles2-sdl.c +++ b/src/platform/sdl/gles2-sdl.c @@ -11,20 +11,19 @@ #endif #include -#include #ifdef __linux__ #include #endif static bool mSDLGLES2Init(struct mSDLRenderer* renderer); -static void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user); static void mSDLGLES2Deinit(struct mSDLRenderer* renderer); void mSDLGLES2Create(struct mSDLRenderer* renderer) { renderer->init = mSDLGLES2Init; renderer->deinit = mSDLGLES2Deinit; - renderer->runloop = mSDLGLES2Runloop; + renderer->runloop = mSDLGLCommonRunloop; + renderer->backend = &renderer->gl2.d; } bool mSDLGLES2Init(struct mSDLRenderer* renderer) { @@ -50,43 +49,19 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) { renderer->gl2.d.swap = mSDLGLCommonSwap; #endif renderer->gl2.d.init(&renderer->gl2.d, 0); - renderer->gl2.d.setDimensions(&renderer->gl2.d, renderer->width, renderer->height); + + struct mRectangle dims = { + .x = 0, + .y = 0, + .width = renderer->width, + .height = renderer->height + }; + renderer->gl2.d.setLayerDimensions(&renderer->gl2.d, VIDEO_LAYER_IMAGE, &dims); mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl2.d); return true; } -void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) { - struct mCoreThread* context = user; - SDL_Event event; - struct VideoBackend* v = &renderer->gl2.d; - - while (mCoreThreadIsActive(context)) { - while (SDL_PollEvent(&event)) { - mSDLHandleEvent(context, &renderer->player, &event); - // Event handling can change the size of the screen - if (renderer->player.windowUpdated) { -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); -#else - renderer->viewportWidth = renderer->player.newWidth; - renderer->viewportHeight = renderer->player.newHeight; - mSDLGLCommonInit(renderer); -#endif - mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, v); - renderer->player.windowUpdated = 0; - } - } - - if (mCoreSyncWaitFrameStart(&context->impl->sync)) { - v->postFrame(v, renderer->outputBuffer); - } - mCoreSyncWaitFrameEnd(&context->impl->sync); - v->drawFrame(v); - v->swap(v); - } -} - void mSDLGLES2Deinit(struct mSDLRenderer* renderer) { if (renderer->gl2.d.deinit) { renderer->gl2.d.deinit(&renderer->gl2.d); diff --git a/src/platform/sdl/main.c b/src/platform/sdl/main.c index 96a797986..f71f1cfc5 100644 --- a/src/platform/sdl/main.c +++ b/src/platform/sdl/main.c @@ -7,12 +7,6 @@ #include -#ifdef USE_GDB_STUB -#include -#endif -#ifdef USE_EDITLINE -#include "feature/editline/cli-el-backend.h" -#endif #ifdef ENABLE_SCRIPTING #include @@ -21,7 +15,6 @@ #endif #endif -#include #include #include #include @@ -61,6 +54,7 @@ int main(int argc, char** argv) { .useBios = true, .rewindEnable = true, .rewindBufferCapacity = 600, + .rewindBufferInterval = 1, .audioBuffers = 1024, .videoSync = false, .audioSync = true, @@ -107,7 +101,7 @@ int main(int argc, char** argv) { return 1; } - renderer.core->desiredVideoDimensions(renderer.core, &renderer.width, &renderer.height); + renderer.core->baseVideoSize(renderer.core, &renderer.width, &renderer.height); renderer.ratio = graphicsOpts.multiplier; if (renderer.ratio == 0) { renderer.ratio = 1; @@ -115,16 +109,6 @@ int main(int argc, char** argv) { opts.width = renderer.width * renderer.ratio; opts.height = renderer.height * renderer.ratio; - struct mCheatDevice* device = NULL; - if (args.cheatsFile && (device = renderer.core->cheatDevice(renderer.core))) { - struct VFile* vf = VFileOpen(args.cheatsFile, O_RDONLY); - if (vf) { - mCheatDeviceClear(device); - mCheatParseFile(device, vf); - vf->close(vf); - } - } - mInputMapInit(&renderer.core->inputMap, &GBAInputInfo); mCoreInitConfig(renderer.core, PORT); mArgumentsApply(&args, &subparser, 1, &renderer.core->config); @@ -188,10 +172,6 @@ int main(int argc, char** argv) { mSDLDetachPlayer(&renderer.events, &renderer.player); mInputMapDeinit(&renderer.core->inputMap); - if (device) { - mCheatDeviceDestroy(device); - } - mSDLDeinit(&renderer); mStandardLoggerDeinit(&_logger); @@ -230,7 +210,7 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) { return 1; } mCoreAutoloadSave(renderer->core); - mCoreAutoloadCheats(renderer->core); + mArgumentsApplyFileLoads(args, renderer->core); #ifdef ENABLE_SCRIPTING struct mScriptBridge* bridge = mScriptBridgeCreate(); #ifdef ENABLE_PYTHON @@ -242,30 +222,20 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) { #endif #ifdef USE_DEBUGGERS - struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core); - if (debugger) { -#ifdef USE_EDITLINE - if (args->debuggerType == DEBUGGER_CLI) { - struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger; - CLIDebuggerAttachBackend(cliDebugger, CLIDebuggerEditLineBackendCreate()); - } -#endif - mDebuggerAttach(debugger, renderer->core); - mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL); -#ifdef ENABLE_SCRIPTING - mScriptBridgeSetDebugger(bridge, debugger); -#endif - } -#endif + struct mDebugger debugger; + mDebuggerInit(&debugger); + bool hasDebugger = mArgumentsApplyDebugger(args, renderer->core, &debugger); - if (args->patch) { - struct VFile* patch = VFileOpen(args->patch, O_RDONLY); - if (patch) { - renderer->core->loadPatch(renderer->core, patch); - } + if (hasDebugger) { + mDebuggerAttach(&debugger, renderer->core); + mDebuggerEnter(&debugger, DEBUGGER_ENTER_MANUAL, NULL); +#ifdef ENABLE_SCRIPTING + mScriptBridgeSetDebugger(bridge, &debugger); +#endif } else { - mCoreAutoloadPatch(renderer->core); + mDebuggerDeinit(&debugger); } +#endif renderer->audio.samples = renderer->core->opts.audioBuffers; renderer->audio.sampleRate = 44100; @@ -275,7 +245,7 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) { if (!didFail) { #if SDL_VERSION_ATLEAST(2, 0, 0) - renderer->core->desiredVideoDimensions(renderer->core, &renderer->width, &renderer->height); + renderer->core->currentVideoSize(renderer->core, &renderer->width, &renderer->height); unsigned width = renderer->width * renderer->ratio; unsigned height = renderer->height * renderer->ratio; if (width != (unsigned) renderer->viewportWidth && height != (unsigned) renderer->viewportHeight) { @@ -321,6 +291,13 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) { mScriptBridgeDestroy(bridge); #endif +#ifdef USE_DEBUGGERS + if (hasDebugger) { + renderer->core->detachDebugger(renderer->core); + mDebuggerDeinit(&debugger); + } +#endif + return didFail; } diff --git a/src/platform/sdl/main.h b/src/platform/sdl/main.h index c97e50e33..10135da2f 100644 --- a/src/platform/sdl/main.h +++ b/src/platform/sdl/main.h @@ -76,6 +76,8 @@ struct mSDLRenderer { struct mGLES2Context gl2; #endif + struct VideoBackend* backend; + #ifdef USE_PIXMAN pixman_image_t* pix; pixman_image_t* screenpix; diff --git a/src/platform/sdl/sw-sdl1.c b/src/platform/sdl/sw-sdl1.c index bfe5d2037..cf917fd0a 100644 --- a/src/platform/sdl/sw-sdl1.c +++ b/src/platform/sdl/sw-sdl1.c @@ -28,7 +28,7 @@ bool mSDLSWInit(struct mSDLRenderer* renderer) { SDL_WM_SetCaption(projectName, ""); unsigned width, height; - renderer->core->desiredVideoDimensions(renderer->core, &width, &height); + renderer->core->baseVideoSize(renderer->core, &width, &height); SDL_Surface* surface = SDL_GetVideoSurface(); SDL_LockSurface(surface); diff --git a/src/platform/sdl/sw-sdl2.c b/src/platform/sdl/sw-sdl2.c index 48afc33a6..75ad1c2ea 100644 --- a/src/platform/sdl/sw-sdl2.c +++ b/src/platform/sdl/sw-sdl2.c @@ -21,7 +21,7 @@ void mSDLSWCreate(struct mSDLRenderer* renderer) { bool mSDLSWInit(struct mSDLRenderer* renderer) { unsigned width, height; - renderer->core->desiredVideoDimensions(renderer->core, &width, &height); + renderer->core->baseVideoSize(renderer->core, &width, &height); renderer->window = SDL_CreateWindow(projectName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer->viewportWidth, renderer->viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer->player.fullscreen)); SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight); renderer->player.window = renderer->window; diff --git a/src/platform/switch/CMakeLists.txt b/src/platform/switch/CMakeLists.txt index a12473b4c..716b33449 100644 --- a/src/platform/switch/CMakeLists.txt +++ b/src/platform/switch/CMakeLists.txt @@ -5,7 +5,7 @@ find_library(GLAPI_LIBRARY glapi REQUIRED) find_library(EGL_LIBRARY EGL REQUIRED) set(OS_DEFINES _GNU_SOURCE IOAPI_NO_64) -list(APPEND CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) +list(APPEND CORE_VFS_SRC ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-dirent.c) list(APPEND GUI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/gui-font.c) include_directories(AFTER ${OPENGLES3_INCLUDE_DIR} ${OPENGL_EGL_INCLUDE_DIR}) @@ -39,11 +39,11 @@ add_custom_command(OUTPUT control.nacp add_custom_command(OUTPUT romfs.bin COMMAND ${CMAKE_COMMAND} -E make_directory romfs - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/res/font-new.png" romfs/ + COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/res/font-new.png" romfs/ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/fileassoc.cfg.in" romfs/ COMMAND ${BUILD_ROMFS} romfs romfs.bin COMMAND ${CMAKE_COMMAND} -E remove_directory romfs - DEPENDS "${CMAKE_SOURCE_DIR}/res/font-new.png" "${CMAKE_CURRENT_SOURCE_DIR}/fileassoc.cfg.in") + DEPENDS "${PROJECT_SOURCE_DIR}/res/font-new.png" "${CMAKE_CURRENT_SOURCE_DIR}/fileassoc.cfg.in") add_custom_target(${BINARY_NAME}.nro ALL ${ELF2NRO} ${BINARY_NAME}.elf ${BINARY_NAME}.nro --romfs=romfs.bin --nacp=control.nacp --icon="${CMAKE_CURRENT_SOURCE_DIR}/icon.jpg" diff --git a/src/platform/switch/gui-font.c b/src/platform/switch/gui-font.c index e164a5e64..16add0128 100644 --- a/src/platform/switch/gui-font.c +++ b/src/platform/switch/gui-font.c @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include -#include +#include #include #include diff --git a/src/platform/switch/main.c b/src/platform/switch/main.c index 9f1e84563..ef3e12164 100644 --- a/src/platform/switch/main.c +++ b/src/platform/switch/main.c @@ -82,6 +82,7 @@ static GLuint insizeLocation; static GLuint colorLocation; static GLuint tex; static GLuint oldTex; +static GLuint screenshotTex; static struct GUIFont* font; static color_t* frameBuffer; @@ -124,6 +125,12 @@ static enum ScreenMode { SM_MAX } screenMode = SM_PA; +static enum FilterMode { + FM_NEAREST, + FM_LINEAR, + FM_MAX +} filterMode = FM_NEAREST; + static bool eglInit() { s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!s_display) { @@ -313,6 +320,9 @@ static void _setup(struct mGUIRunner* runner) { if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode < SM_MAX) { screenMode = mode; } + if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) { + filterMode = mode; + } runner->core->setAudioBufferSize(runner->core, SAMPLES); } @@ -330,6 +340,9 @@ static void _gameLoaded(struct mGUIRunner* runner) { if (mCoreConfigGetUIntValue(&runner->config, "screenMode", &mode) && mode < SM_MAX) { screenMode = mode; } + if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) { + filterMode = mode; + } int fakeBool; if (mCoreConfigGetIntValue(&runner->config, "interframeBlending", &fakeBool)) { @@ -379,8 +392,8 @@ static void _gameUnloaded(struct mGUIRunner* runner) { static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, bool faded, bool blendTop) { glViewport(0, 1080 - vheight, vwidth, vheight); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filterMode == FM_LINEAR ? GL_LINEAR : GL_NEAREST); glUseProgram(program); glBindVertexArray(vao); @@ -478,7 +491,7 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) { } unsigned width, height; - runner->core->desiredVideoDimensions(runner->core, &width, &height); + runner->core->currentVideoSize(runner->core, &width, &height); glActiveTexture(GL_TEXTURE0); if (usePbo) { @@ -493,11 +506,16 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) { } if (interframeBlending) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBindTexture(GL_TEXTURE_2D, oldTex); _drawTex(runner, width, height, faded, false); glBindTexture(GL_TEXTURE_2D, tex); _drawTex(runner, width, height, faded, true); } else { + glDisable(GL_BLEND); + _drawTex(runner, width, height, faded, false); } @@ -523,10 +541,15 @@ static void _drawFrame(struct mGUIRunner* runner, bool faded) { static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) { glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glBindTexture(GL_TEXTURE_2D, screenshotTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + runner->core->currentVideoSize(runner->core, &width, &height); + glDisable(GL_BLEND); + bool wasPbo = usePbo; + usePbo = false; _drawTex(runner, width, height, faded, false); + usePbo = wasPbo; } static uint16_t _pollGameInput(struct mGUIRunner* runner) { @@ -702,14 +725,18 @@ static void glInit(void) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glGenTextures(1, &oldTex); glBindTexture(GL_TEXTURE_2D, oldTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glGenTextures(1, &screenshotTex); + glBindTexture(GL_TEXTURE_2D, screenshotTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glGenBuffers(1, &pbo); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); @@ -790,6 +817,7 @@ static void glDeinit(void) { glDeleteFramebuffers(1, ©Fbo); glDeleteTextures(1, &tex); glDeleteTextures(1, &oldTex); + glDeleteTextures(1, &screenshotTex); glDeleteBuffers(1, &vbo); glDeleteProgram(program); glDeleteVertexArrays(1, &vao); @@ -964,11 +992,22 @@ int main(int argc, char* argv[]) { }, .nStates = 16 }, + { + .title = "Filtering", + .data = GUI_V_S("filterMode"), + .submenu = 0, + .state = FM_NEAREST, + .validStates = (const char*[]) { + "None", + "Bilinear", + }, + .nStates = 2 + }, { .title = "GPU-accelerated renderer", .data = GUI_V_S("hwaccelVideo"), .submenu = 0, - .state = 0, + .state = FM_NEAREST, .validStates = (const char*[]) { "Off", "On", @@ -1010,7 +1049,7 @@ int main(int argc, char* argv[]) { .nStates = 2 }, }, - .nConfigExtra = 5, + .nConfigExtra = 6, .setup = _setup, .teardown = NULL, .gameLoaded = _gameLoaded, diff --git a/src/platform/test/CMakeLists.txt b/src/platform/test/CMakeLists.txt index 5e20cb41e..3172c6c88 100644 --- a/src/platform/test/CMakeLists.txt +++ b/src/platform/test/CMakeLists.txt @@ -8,7 +8,7 @@ if(BUILD_PERF) target_link_libraries(${BINARY_NAME}-perf ${BINARY_NAME} ${PERF_LIB} ${OS_LIB}) set_target_properties(${BINARY_NAME}-perf PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") install(TARGETS ${BINARY_NAME}-perf DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-perf) - install(FILES "${CMAKE_SOURCE_DIR}/tools/perf.py" DESTINATION "${LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) + install(FILES "${PROJECT_SOURCE_DIR}/tools/perf.py" DESTINATION "${LIBDIR}/${BINARY_NAME}" COMPONENT ${BINARY_NAME}-perf) endif() if(BUILD_TEST) @@ -27,7 +27,7 @@ if(BUILD_SUITE) link_directories(${CMOCKA_LIBRARY_DIRS}) foreach(TEST IN LISTS TEST_SRC) - string(REPLACE "${CMAKE_SOURCE_DIR}/src/" "" TEST_NAME "${TEST}") + string(REPLACE "${PROJECT_SOURCE_DIR}/src/" "" TEST_NAME "${TEST}") string(REPLACE "/" "-" TEST_NAME "${TEST_NAME}") string(REPLACE "-test" "" TEST_NAME "${TEST_NAME}") string(REPLACE ".c" "" TEST_NAME "${TEST_NAME}") diff --git a/src/platform/test/cinema-main.c b/src/platform/test/cinema-main.c index 28bb07693..a990b5599 100644 --- a/src/platform/test/cinema-main.c +++ b/src/platform/test/cinema-main.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -731,8 +731,8 @@ static struct VDir* _makeOutDir(const char* testName) { static void _writeImage(struct VFile* vf, const struct CInemaImage* image) { png_structp png = PNGWriteOpen(vf); - png_infop info = PNGWriteHeader(png, image->width, image->height); - if (!PNGWritePixels(png, image->width, image->height, image->stride, image->data)) { + png_infop info = PNGWriteHeader(png, image->width, image->height, mCOLOR_NATIVE); + if (!PNGWritePixels(png, image->width, image->height, image->stride, image->data, mCOLOR_NATIVE)) { CIerr(0, "Could not write output image\n"); } PNGWriteClose(png, info); @@ -1032,7 +1032,7 @@ void CInemaTestRun(struct CInemaTest* test) { return; } struct CInemaImage image; - core->desiredVideoDimensions(core, &image.width, &image.height); + core->baseVideoSize(core, &image.width, &image.height); ssize_t bufferSize = image.width * image.height * BYTES_PER_PIXEL; image.data = malloc(bufferSize); image.stride = image.width; @@ -1075,7 +1075,7 @@ void CInemaTestRun(struct CInemaTest* test) { for (frame = 0; frame < skip; ++frame) { core->runFrame(core); } - core->desiredVideoDimensions(core, &image.width, &image.height); + core->currentVideoSize(core, &image.width, &image.height); #ifdef USE_FFMPEG struct FFmpegDecoder decoder; @@ -1139,7 +1139,7 @@ void CInemaTestRun(struct CInemaTest* test) { break; } CIlog(3, "Test frame: %u\n", frameCounter); - core->desiredVideoDimensions(core, &image.width, &image.height); + core->currentVideoSize(core, &image.width, &image.height); uint8_t* diff = NULL; struct CInemaImage expected = { .data = NULL, @@ -1177,7 +1177,7 @@ void CInemaTestRun(struct CInemaTest* test) { if (test->status == CI_ERROR) { break; } - bool failed = false; + bool failed = true; if (baselineFound) { int max = 0; failed = !_compareImages(test, &image, &expected, &max, diffs ? &diff : NULL); @@ -1365,6 +1365,7 @@ static THREAD_ENTRY CInemaJob(void* context) { CIflush(&stream.err, stderr); StringListDeinit(&stream.err.lines); StringListDeinit(&stream.err.partial); + THREAD_EXIT(0); } void _log(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) { diff --git a/src/platform/test/fuzz-main.c b/src/platform/test/fuzz-main.c index 84e71fffa..eb42b449b 100644 --- a/src/platform/test/fuzz-main.c +++ b/src/platform/test/fuzz-main.c @@ -8,8 +8,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -20,19 +20,21 @@ #include #include -#define FUZZ_OPTIONS "F:NO:S:V:" +#define FUZZ_OPTIONS "F:M:NO:S:V:" #define FUZZ_USAGE \ "Additional options:\n" \ " -F FRAMES Run for the specified number of FRAMES before exiting\n" \ " -N Disable video rendering entirely\n" \ " -O OFFSET Offset to apply savestate overlay\n" \ " -V FILE Overlay a second savestate over the loaded savestate\n" \ + " -M FILE Attach a memory access log file\n" \ struct FuzzOpts { bool noVideo; int frames; size_t overlayOffset; char* ssOverlay; + char* accessLog; }; static void _fuzzRunloop(struct mCore* core, int frames); @@ -98,9 +100,6 @@ int main(int argc, char** argv) { cleanExit = false; goto loadError; } - if (args.patch) { - core->loadPatch(core, VFileOpen(args.patch, O_RDONLY)); - } struct VFile* savestate = 0; struct VFile* savestateOverlay = 0; @@ -119,16 +118,24 @@ int main(int argc, char** argv) { core->reset(core); - struct mCheatDevice* device; - if (args.cheatsFile && (device = core->cheatDevice(core))) { - struct VFile* vf = VFileOpen(args.cheatsFile, O_RDONLY); - if (vf) { - mCheatDeviceClear(device); - mCheatParseFile(device, vf); - vf->close(vf); - } + struct mDebugger debugger; + struct mDebuggerAccessLogger accessLog; + bool hasDebugger = false; + + mDebuggerInit(&debugger); + + if (fuzzOpts.accessLog) { + mDebuggerAttach(&debugger, core); + + struct VFile* vf = VFileOpen(fuzzOpts.accessLog, O_RDWR); + mDebuggerAccessLoggerInit(&accessLog); + mDebuggerAttachModule(&debugger, &accessLog.d); + mDebuggerAccessLoggerOpen(&accessLog, vf, O_RDWR); + hasDebugger = true; } + mArgumentsApplyFileLoads(&args, core); + if (savestate) { if (!savestateOverlay) { mCoreLoadStateNamed(core, savestate, 0); @@ -146,11 +153,17 @@ int main(int argc, char** argv) { savestate = 0; } - blip_set_rates(core->getAudioChannel(core, 0), GBA_ARM7TDMI_FREQUENCY, 0x8000); - blip_set_rates(core->getAudioChannel(core, 1), GBA_ARM7TDMI_FREQUENCY, 0x8000); + blip_set_rates(core->getAudioChannel(core, 0), core->frequency(core), 0x8000); + blip_set_rates(core->getAudioChannel(core, 1), core->frequency(core), 0x8000); _fuzzRunloop(core, fuzzOpts.frames); + if (hasDebugger) { + core->detachDebugger(core); + mDebuggerAccessLoggerDeinit(&accessLog); + mDebuggerDeinit(&debugger); + } + core->unloadROM(core); if (savestate) { @@ -192,6 +205,9 @@ static bool _parseFuzzOpts(struct mSubParser* parser, int option, const char* ar case 'F': opts->frames = strtoul(arg, 0, 10); return !errno; + case 'M': + opts->accessLog = strdup(arg); + return true; case 'N': opts->noVideo = true; return true; diff --git a/src/platform/test/rom-test-main.c b/src/platform/test/rom-test-main.c index 6a8962743..8c0d4fd3d 100644 --- a/src/platform/test/rom-test-main.c +++ b/src/platform/test/rom-test-main.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2022 Jeffrey Pfau +/* Copyright (c) 2013-2023 Jeffrey Pfau * Copyright (c) 2022 Felix Jones * * This Source Code Form is subject to the terms of the Mozilla Public @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef M_CORE_GBA #include #endif @@ -137,38 +138,52 @@ int main(int argc, char * argv[]) { if (!mCoreLoadFile(core, args.fname)) { goto loadError; } - if (args.patch) { - core->loadPatch(core, VFileOpen(args.patch, O_RDONLY)); - } - struct VFile* savestate = NULL; +#ifdef USE_DEBUGGERS + struct mDebugger debugger; + mDebuggerInit(&debugger); + bool hasDebugger = mArgumentsApplyDebugger(&args, core, &debugger); - if (args.savestate) { - savestate = VFileOpen(args.savestate, O_RDONLY); + if (hasDebugger) { + mDebuggerAttach(&debugger, core); + mDebuggerEnter(&debugger, DEBUGGER_ENTER_MANUAL, NULL); + } else { + mDebuggerDeinit(&debugger); } +#endif core->reset(core); - struct mCheatDevice* device; - if (args.cheatsFile && (device = core->cheatDevice(core))) { - struct VFile* vf = VFileOpen(args.cheatsFile, O_RDONLY); - if (vf) { - mCheatDeviceClear(device); - mCheatParseFile(device, vf); - vf->close(vf); - } - } + mArgumentsApplyFileLoads(&args, core); + struct VFile* savestate = NULL; + if (args.savestate) { + savestate = VFileOpen(args.savestate, O_RDONLY); + } if (savestate) { mCoreLoadStateNamed(core, savestate, 0); savestate->close(savestate); } +#ifdef USE_DEBUGGERS + if (hasDebugger) { + do { + mDebuggerRun(&debugger); + } while (!_dispatchExiting && debugger.state != DEBUGGER_SHUTDOWN); + } else +#endif do { core->runLoop(core); } while (!_dispatchExiting); core->unloadROM(core); + +#ifdef USE_DEBUGGERS + if (hasDebugger) { + core->detachDebugger(core); + mDebuggerDeinit(&debugger); + } +#endif cleanExit = true; loadError: diff --git a/src/platform/video-backend.h b/src/platform/video-backend.h deleted file mode 100644 index 6d714629a..000000000 --- a/src/platform/video-backend.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2013-2015 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/. */ -#ifndef VIDEO_BACKEND_H -#define VIDEO_BACKEND_H - -#include - -CXX_GUARD_START - -#ifdef _WIN32 -#include -typedef HWND WHandle; -#else -typedef void* WHandle; -#endif - -struct VideoBackend { - void (*init)(struct VideoBackend*, WHandle handle); - void (*deinit)(struct VideoBackend*); - void (*setDimensions)(struct VideoBackend*, unsigned width, unsigned height); - void (*swap)(struct VideoBackend*); - void (*clear)(struct VideoBackend*); - void (*resized)(struct VideoBackend*, unsigned w, unsigned h); - void (*postFrame)(struct VideoBackend*, const void* frame); - void (*drawFrame)(struct VideoBackend*); - void (*setMessage)(struct VideoBackend*, const char* message); - void (*clearMessage)(struct VideoBackend*); - - void* user; - unsigned width; - unsigned height; - - bool filter; - bool lockAspectRatio; - bool lockIntegerScaling; - bool interframeBlending; -}; - -struct VideoShader { - const char* name; - const char* author; - const char* description; - void* preprocessShader; - void* passes; - size_t nPasses; -}; - -CXX_GUARD_END - -#endif diff --git a/src/platform/wii/CMakeLists.txt b/src/platform/wii/CMakeLists.txt index 3fead14c8..569408523 100644 --- a/src/platform/wii/CMakeLists.txt +++ b/src/platform/wii/CMakeLists.txt @@ -9,7 +9,7 @@ if(WIIDRC_LIBRARY) endif() set(OS_DEFINES _GNU_SOURCE COLOR_16_BIT COLOR_5_6_5 IOAPI_NO_64 FIXED_ROM_BUFFER) -list(APPEND CORE_VFS_SRC ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-dirent.c ${CMAKE_SOURCE_DIR}/src/util/vfs/vfs-devlist.c) +list(APPEND CORE_VFS_SRC ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-fd.c ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-dirent.c ${PROJECT_SOURCE_DIR}/src/util/vfs/vfs-devlist.c) include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -30,8 +30,8 @@ if(WIIDRC_LIBRARY) endif() add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.tpl - COMMAND ${GXTEXCONV} -i ${CMAKE_SOURCE_DIR}/res/font2x.png -o font.tpl colfmt=5 mipmap=no - MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/res/font2x.png + COMMAND ${GXTEXCONV} -i ${PROJECT_SOURCE_DIR}/res/font2x.png -o font.tpl colfmt=5 mipmap=no + MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/res/font2x.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c @@ -40,8 +40,8 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/font.c WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.tpl - COMMAND ${GXTEXCONV} -i ${CMAKE_SOURCE_DIR}/res/icons2x.png -o icons.tpl colfmt=5 mipmap=no - MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/res/icons2x.png + COMMAND ${GXTEXCONV} -i ${PROJECT_SOURCE_DIR}/res/icons2x.png -o icons.tpl colfmt=5 mipmap=no + MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/res/icons2x.png WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icons.c diff --git a/src/platform/wii/CMakeToolchain.txt b/src/platform/wii/CMakeToolchain.txt index 887efd669..0370f2c04 100644 --- a/src/platform/wii/CMakeToolchain.txt +++ b/src/platform/wii/CMakeToolchain.txt @@ -7,6 +7,7 @@ set(link_flags "-L${DEVKITPRO}/libogc/lib/wii ${arch_flags}") set(CMAKE_SYSTEM_PROCESSOR powerpc CACHE INTERNAL "processor") set(CMAKE_LIBRARY_ARCHITECTURE powerpc-none-eabi CACHE INTERNAL "abi") +set(CMAKE_REQUIRED_LIBRARIES ogc) set(WII ON) add_definitions(-DGEKKO) diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index 312388347..db3ed7242 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -271,7 +271,7 @@ int main(int argc, char* argv[]) { memset(audioBuffer, 0, sizeof(audioBuffer)); #ifdef FIXED_ROM_BUFFER - romBufferSize = SIZE_CART0; + romBufferSize = GBA_SIZE_ROM0; romBuffer = SYS_GetArena2Lo(); SYS_SetArena2Lo((void*)((intptr_t) romBuffer + romBufferSize)); #endif @@ -1511,7 +1511,7 @@ void _prepareForFrame(struct mGUIRunner* runner) { } void _drawFrame(struct mGUIRunner* runner, bool faded) { - runner->core->desiredVideoDimensions(runner->core, &corew, &coreh); + runner->core->currentVideoSize(runner->core, &corew, &coreh); uint32_t color = 0xFFFFFF3F; if (!faded) { color |= 0xC0; diff --git a/src/platform/windows/vfs-w32.c b/src/platform/windows/vfs-w32.c index bfa2e30a3..b160bc588 100644 --- a/src/platform/windows/vfs-w32.c +++ b/src/platform/windows/vfs-w32.c @@ -151,7 +151,12 @@ bool _vdwDeleteFile(struct VDir* vd, const char* path) { MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw, MAX_PATH); StringCchPrintfW(combined, MAX_PATH, L"%ws\\%ws", dir, pathw); - return DeleteFileW(combined); + DWORD attrs = GetFileAttributesW(combined); + if (attrs & FILE_ATTRIBUTE_DIRECTORY) { + return RemoveDirectoryW(combined); + } else { + return DeleteFileW(combined); + } } const char* _vdweName(struct VDirEntry* vde) { @@ -183,4 +188,4 @@ bool VDirCreate(const char* path) { return true; } return false; -} \ No newline at end of file +} diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt index 5cfb4ff41..0f64514c0 100644 --- a/src/script/CMakeLists.txt +++ b/src/script/CMakeLists.txt @@ -1,6 +1,9 @@ include(ExportDirectory) set(SOURCE_FILES + canvas.c context.c + input.c + image.c socket.c stdlib.c types.c) @@ -9,11 +12,22 @@ set(TEST_FILES test/classes.c test/types.c) +if(USE_JSON_C) + list(APPEND SOURCE_FILES storage.c) +endif() + if(USE_LUA) list(APPEND SOURCE_FILES engines/lua.c) list(APPEND TEST_FILES - test/stdlib.c - test/lua.c) + test/context.c + test/image.c + test/input.c + test/lua.c + test/stdlib.c) + + if(USE_JSON_C) + list(APPEND TEST_FILES test/storage.c) + endif() endif() source_group("Scripting" FILES ${SOURCE_FILES}) diff --git a/src/script/canvas.c b/src/script/canvas.c new file mode 100644 index 000000000..5e931943d --- /dev/null +++ b/src/script/canvas.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2013-2023 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 + +#include +#include +#include + +struct mScriptCanvasContext; +struct mScriptCanvasLayer { + struct VideoBackend* backend; + enum VideoLayer layer; + struct mImage* image; + int x; + int y; + unsigned scale; + bool dirty; + bool sizeDirty; + bool dimsDirty; + bool contentsDirty; +}; + +struct mScriptCanvasContext { + struct mScriptCanvasLayer overlays[VIDEO_LAYER_OVERLAY_COUNT]; + struct VideoBackend* backend; + struct mScriptContext* context; + uint32_t frameCbid; + unsigned scale; +}; + +mSCRIPT_DECLARE_STRUCT(mScriptCanvasContext); +mSCRIPT_DECLARE_STRUCT(mScriptCanvasLayer); + +static void mScriptCanvasLayerDestroy(struct mScriptCanvasLayer* layer); +static void mScriptCanvasLayerUpdate(struct mScriptCanvasLayer* layer); + +static int _getNextAvailableOverlay(struct mScriptCanvasContext* context) { + if (!context->backend) { + return -1; + } + size_t i; + for (i = 0; i < VIDEO_LAYER_OVERLAY_COUNT; ++i) { + int w = -1, h = -1; + context->backend->imageSize(context->backend, VIDEO_LAYER_OVERLAY0 + i, &w, &h); + if (w <= 0 && h <= 0) { + return i; + } + } + return -1; +} + +static void mScriptCanvasContextDeinit(struct mScriptCanvasContext* context) { + size_t i; + for (i = 0; i < VIDEO_LAYER_OVERLAY_COUNT; ++i) { + if (context->overlays[i].image) { + mScriptCanvasLayerDestroy(&context->overlays[i]); + } + } +} + +void mScriptCanvasUpdateBackend(struct mScriptContext* context, struct VideoBackend* backend) { + struct mScriptValue* value = mScriptContextGetGlobal(context, "canvas"); + if (!value) { + return; + } + struct mScriptCanvasContext* canvas = value->value.opaque; + canvas->backend = backend; + size_t i; + for (i = 0; i < VIDEO_LAYER_OVERLAY_COUNT; ++i) { + struct mScriptCanvasLayer* layer = &canvas->overlays[i]; + layer->backend = backend; + layer->dirty = true; + layer->dimsDirty = true; + layer->sizeDirty = true; + layer->contentsDirty = true; + } +} + +void mScriptCanvasSetInternalScale(struct mScriptContext* context, unsigned scale) { + struct mScriptValue* value = mScriptContextGetGlobal(context, "canvas"); + if (!value) { + return; + } + struct mScriptCanvasContext* canvas = value->value.opaque; + if (scale < 1) { + scale = 1; + } + canvas->scale = scale; + size_t i; + for (i = 0; i < VIDEO_LAYER_OVERLAY_COUNT; ++i) { + canvas->overlays[i].scale = scale; + } +} + +static void _mScriptCanvasUpdate(struct mScriptCanvasContext* canvas) { + size_t i; + for (i = 0; i < VIDEO_LAYER_OVERLAY_COUNT; ++i) { + mScriptCanvasLayerUpdate(&canvas->overlays[i]); + } +} + +static unsigned _mScriptCanvasWidth(struct mScriptCanvasContext* canvas) { + if (!canvas->backend) { + return 0; + } + unsigned w, h; + VideoBackendGetFrameSize(canvas->backend, &w, &h); + return w / canvas->scale; +} + +static unsigned _mScriptCanvasHeight(struct mScriptCanvasContext* canvas) { + if (!canvas->backend) { + return 0; + } + unsigned w, h; + VideoBackendGetFrameSize(canvas->backend, &w, &h); + return h / canvas->scale; +} + +static int _mScriptCanvasScreenWidth(struct mScriptCanvasContext* canvas) { + if (!canvas->backend) { + return 0; + } + struct mRectangle dims; + canvas->backend->layerDimensions(canvas->backend, VIDEO_LAYER_IMAGE, &dims); + return dims.width / canvas->scale; +} + +static int _mScriptCanvasScreenHeight(struct mScriptCanvasContext* canvas) { + if (!canvas->backend) { + return 0; + } + struct mRectangle dims; + canvas->backend->layerDimensions(canvas->backend, VIDEO_LAYER_IMAGE, &dims); + return dims.height / canvas->scale; +} + +void mScriptCanvasUpdate(struct mScriptContext* context) { + struct mScriptValue* value = mScriptContextGetGlobal(context, "canvas"); + if (!value) { + return; + } + struct mScriptCanvasContext* canvas = value->value.opaque; + _mScriptCanvasUpdate(canvas); +} + +static struct mScriptValue* mScriptCanvasLayerCreate(struct mScriptCanvasContext* context, int w, int h) { + if (w <= 0 || h <= 0) { + return NULL; + } + int next = _getNextAvailableOverlay(context); + if (next < 0) { + return NULL; + } + + struct mScriptCanvasLayer* layer = &context->overlays[next]; + if (layer->image) { + // This shouldn't exist yet + abort(); + } + + layer->image = mImageCreate(w, h, mCOLOR_ABGR8); + layer->dirty = true; + layer->dimsDirty = true; + layer->sizeDirty = true; + layer->contentsDirty = true; + layer->scale = context->scale; + mScriptCanvasLayerUpdate(layer); + + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptCanvasLayer)); + value->value.opaque = layer; + return value; +} + +static void mScriptCanvasLayerDestroy(struct mScriptCanvasLayer* layer) { + struct mRectangle frame = {0}; + if (layer->backend) { + layer->backend->setLayerDimensions(layer->backend, layer->layer, &frame); + layer->backend->setImageSize(layer->backend, layer->layer, 0, 0); + } + mImageDestroy(layer->image); + layer->image = NULL; +} + +static void mScriptCanvasLayerUpdate(struct mScriptCanvasLayer* layer) { + if (!layer->dirty || !layer->image || !layer->backend) { + return; + } + + struct VideoBackend* backend = layer->backend; + if (layer->sizeDirty) { + backend->setImageSize(backend, layer->layer, layer->image->width, layer->image->height); + layer->sizeDirty = false; + // Resizing the image invalidates the contents in many backends + layer->contentsDirty = true; + } + if (layer->dimsDirty) { + struct mRectangle frame = { + .x = layer->x * layer->scale, + .y = layer->y * layer->scale, + .width = layer->image->width * layer->scale, + .height = layer->image->height * layer->scale, + }; + backend->setLayerDimensions(backend, layer->layer, &frame); + layer->dimsDirty = false; + } + if (layer->contentsDirty) { + backend->setImage(backend, layer->layer, layer->image->data); + layer->contentsDirty = false; + } + layer->dirty = false; +} + + +static void mScriptCanvasLayerSetPosition(struct mScriptCanvasLayer* layer, int32_t x, int32_t y) { + layer->x = x; + layer->y = y; + layer->dimsDirty = true; + layer->dirty = true; +} + +static void mScriptCanvasLayerInvalidate(struct mScriptCanvasLayer* layer) { + layer->contentsDirty = true; + layer->dirty = true; +} + +void mScriptContextAttachCanvas(struct mScriptContext* context) { + struct mScriptCanvasContext* canvas = calloc(1, sizeof(*canvas)); + canvas->scale = 1; + size_t i; + for (i = 0; i < VIDEO_LAYER_OVERLAY_COUNT; ++i) { + canvas->overlays[i].layer = VIDEO_LAYER_OVERLAY0 + i; + } + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptCanvasContext)); + value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; + value->value.opaque = canvas; + + canvas->context = context; + struct mScriptValue* lambda = mScriptObjectBindLambda(value, "update", NULL); + canvas->frameCbid = mScriptContextAddCallback(context, "frame", lambda); + mScriptValueDeref(lambda); + + mScriptContextSetGlobal(context, "canvas", value); + mScriptContextSetDocstring(context, "canvas", "Singleton instance of struct::mScriptCanvasContext"); +} + +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCanvasContext, _deinit, mScriptCanvasContextDeinit, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCanvasContext, W(mScriptCanvasLayer), newLayer, mScriptCanvasLayerCreate, 2, S32, width, S32, height); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCanvasContext, update, _mScriptCanvasUpdate, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCanvasContext, U32, width, _mScriptCanvasWidth, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCanvasContext, U32, height, _mScriptCanvasHeight, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCanvasContext, S32, screenWidth, _mScriptCanvasScreenWidth, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCanvasContext, S32, screenHeight, _mScriptCanvasScreenHeight, 0); + +mSCRIPT_DEFINE_STRUCT(mScriptCanvasContext) + mSCRIPT_DEFINE_CLASS_DOCSTRING( + "A canvas that can be used for drawing images on or around the screen." + ) + mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptCanvasContext) + mSCRIPT_DEFINE_DOCSTRING("Create a new layer of a given size. If multiple layers overlap, the most recently created one takes priority.") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasContext, newLayer) + mSCRIPT_DEFINE_DOCSTRING("Update all layers marked as having pending changes") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasContext, update) + mSCRIPT_DEFINE_DOCSTRING("Get the width of the canvas") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasContext, width) + mSCRIPT_DEFINE_DOCSTRING("Get the height of the canvas") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasContext, height) + mSCRIPT_DEFINE_DOCSTRING("Get the width of the emulated screen") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasContext, screenWidth) + mSCRIPT_DEFINE_DOCSTRING("Get the height of the emulated screen") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasContext, screenHeight) +mSCRIPT_DEFINE_END; + +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCanvasLayer, update, mScriptCanvasLayerInvalidate, 0); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCanvasLayer, setPosition, mScriptCanvasLayerSetPosition, 2, S32, x, S32, y); + +mSCRIPT_DEFINE_STRUCT(mScriptCanvasLayer) + mSCRIPT_DEFINE_CLASS_DOCSTRING( + "An individual layer of a drawable canvas." + ) + mSCRIPT_DEFINE_DOCSTRING("Mark the contents of the layer as needed to be repainted") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasLayer, update) + mSCRIPT_DEFINE_DOCSTRING("Set the position of the layer in the canvas") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCanvasLayer, setPosition) + mSCRIPT_DEFINE_DOCSTRING("The image that has the pixel contents of the image") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptCanvasLayer, PS(mImage), image) + mSCRIPT_DEFINE_DOCSTRING("The current x (horizontal) position of this layer") + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(mScriptCanvasLayer, S32, x) + mSCRIPT_DEFINE_DOCSTRING("The current y (vertical) position of this layer") + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(mScriptCanvasLayer, S32, y) +mSCRIPT_DEFINE_END; diff --git a/src/script/context.c b/src/script/context.c index fa1a0b4a2..090daf66d 100644 --- a/src/script/context.c +++ b/src/script/context.c @@ -7,6 +7,27 @@ #ifdef USE_LUA #include #endif +#include + +static ThreadLocal _threadContext; + +#ifdef USE_PTHREADS +static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT; + +static void _createTLS(void) { + ThreadLocalInitKey(&_threadContext); +} +#elif _WIN32 +static INIT_ONCE _contextOnce = INIT_ONCE_STATIC_INIT; + +static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) { + UNUSED(once); + UNUSED(param); + UNUSED(context); + ThreadLocalInitKey(&_threadContext); + return TRUE; +} +#endif #define KEY_NAME_MAX 128 @@ -17,8 +38,10 @@ struct mScriptFileInfo { }; struct mScriptCallbackInfo { + struct mScriptValue* fn; const char* callback; - size_t id; + uint32_t id; + bool oneshot; }; static void _engineContextDestroy(void* ctx) { @@ -56,23 +79,44 @@ static void _contextFindForFile(const char* key, void* value, void* user) { } } +static void _freeTable(void* data) { + struct Table* table = data; + + struct TableIterator iter; + if (TableIteratorStart(table, &iter)) { + do { + struct mScriptCallbackInfo* info = TableIteratorGetValue(table, &iter); + mScriptValueDeref(info->fn); + } while (TableIteratorNext(table, &iter)); + } + + TableDeinit(table); + free(table); +} + void mScriptContextInit(struct mScriptContext* context) { +#ifdef USE_PTHREADS + pthread_once(&_contextOnce, _createTLS); +#elif _WIN32 + InitOnceExecuteOnce(&_contextOnce, _createTLS, NULL, 0); +#endif HashTableInit(&context->rootScope, 0, (void (*)(void*)) mScriptValueDeref); HashTableInit(&context->engines, 0, _engineContextDestroy); mScriptListInit(&context->refPool, 0); TableInit(&context->weakrefs, 0, (void (*)(void*)) mScriptValueDeref); context->nextWeakref = 1; - HashTableInit(&context->callbacks, 0, (void (*)(void*)) mScriptValueDeref); + HashTableInit(&context->callbacks, 0, _freeTable); TableInit(&context->callbackId, 0, free); context->nextCallbackId = 1; context->constants = NULL; HashTableInit(&context->docstrings, 0, NULL); + context->threadDepth = 0; } void mScriptContextDeinit(struct mScriptContext* context) { HashTableDeinit(&context->rootScope); - HashTableDeinit(&context->weakrefs); mScriptContextDrainPool(context); + HashTableDeinit(&context->weakrefs); mScriptListDeinit(&context->refPool); HashTableDeinit(&context->callbacks); TableDeinit(&context->callbackId); @@ -84,14 +128,6 @@ void mScriptContextFillPool(struct mScriptContext* context, struct mScriptValue* if (value->refs == mSCRIPT_VALUE_UNREF) { return; } - switch (value->type->base) { - case mSCRIPT_TYPE_SINT: - case mSCRIPT_TYPE_UINT: - case mSCRIPT_TYPE_FLOAT: - return; - default: - break; - } struct mScriptValue* poolEntry = mScriptListAppend(&context->refPool); poolEntry->type = mSCRIPT_TYPE_MS_WRAPPER; @@ -102,9 +138,12 @@ void mScriptContextFillPool(struct mScriptContext* context, struct mScriptValue* void mScriptContextDrainPool(struct mScriptContext* context) { size_t i; for (i = 0; i < mScriptListSize(&context->refPool); ++i) { - struct mScriptValue* value = mScriptValueUnwrap(mScriptListGetPointer(&context->refPool, i)); - if (value) { + struct mScriptValue* value = mScriptListGetPointer(&context->refPool, i); + if (value->type->base == mSCRIPT_TYPE_WRAPPER) { + value = mScriptValueUnwrap(value); mScriptValueDeref(value); + } else if (value->type == mSCRIPT_TYPE_MS_WEAKREF) { + mScriptContextClearWeakref(context, value->value.u32); } } mScriptListClear(&context->refPool); @@ -201,43 +240,79 @@ void mScriptContextClearWeakref(struct mScriptContext* context, uint32_t weakref TableRemove(&context->weakrefs, weakref); } -void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback) { - struct mScriptValue* list = HashTableLookup(&context->callbacks, callback); - if (!list) { - return; - } - size_t i; - for (i = 0; i < mScriptListSize(list->value.list); ++i) { - struct mScriptFrame frame; - struct mScriptValue* fn = mScriptListGetPointer(list->value.list, i); - if (!fn->type) { - continue; - } - mScriptFrameInit(&frame); - if (fn->type->base == mSCRIPT_TYPE_WRAPPER) { - fn = mScriptValueUnwrap(fn); - } - mScriptInvoke(fn, &frame); - mScriptFrameDeinit(&frame); - } +void mScriptContextDisownWeakref(struct mScriptContext* context, uint32_t weakref) { + struct mScriptValue* poolEntry = mScriptListAppend(&context->refPool); + poolEntry->type = mSCRIPT_TYPE_MS_WEAKREF; + poolEntry->value.u32 = weakref; + poolEntry->refs = mSCRIPT_VALUE_UNREF; } -uint32_t mScriptContextAddCallback(struct mScriptContext* context, const char* callback, struct mScriptValue* fn) { - if (fn->type->base != mSCRIPT_TYPE_FUNCTION) { +void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback, struct mScriptList* args) { + struct Table* table = HashTableLookup(&context->callbacks, callback); + if (!table) { + return; + } + struct TableIterator iter; + if (!TableIteratorStart(table, &iter)) { + return; + } + + struct UInt32List oneshots; + UInt32ListInit(&oneshots, 0); + do { + struct mScriptFrame frame; + struct mScriptCallbackInfo* info = TableIteratorGetValue(table, &iter); + struct mScriptValue* fn = mScriptContextAccessWeakref(context, info->fn); + if (fn) { + mScriptFrameInit(&frame); + if (args) { + mScriptListCopy(&frame.arguments, args); + } + mScriptContextInvoke(context, fn, &frame); + mScriptFrameDeinit(&frame); + } + + if (info->oneshot) { + *UInt32ListAppend(&oneshots) = info->id; + } + } while (TableIteratorNext(table, &iter)); + + size_t i; + for (i = 0; i < UInt32ListSize(&oneshots); ++i) { + mScriptContextRemoveCallback(context, *UInt32ListGetPointer(&oneshots, i)); + } + UInt32ListDeinit(&oneshots); +} + +static uint32_t mScriptContextAddCallbackInternal(struct mScriptContext* context, const char* callback, struct mScriptValue* fn, bool oneshot) { + if (fn->type == mSCRIPT_TYPE_MS_WEAKREF) { + struct mScriptValue* weakref = mScriptContextAccessWeakref(context, fn); + if (!weakref) { + return 0; + } + if (weakref->type->base != mSCRIPT_TYPE_FUNCTION) { + return 0; + } + } else if (fn->type->base != mSCRIPT_TYPE_FUNCTION) { return 0; } - struct mScriptValue* list = HashTableLookup(&context->callbacks, callback); - if (!list) { - list = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST); - HashTableInsert(&context->callbacks, callback, list); + struct Table* table = HashTableLookup(&context->callbacks, callback); + if (!table) { + table = calloc(1, sizeof(*table)); + TableInit(table, 0, NULL); + HashTableInsert(&context->callbacks, callback, table); } struct mScriptCallbackInfo* info = malloc(sizeof(*info)); // Steal the string from the table key, since it's guaranteed to outlive this struct struct TableIterator iter; HashTableIteratorLookup(&context->callbacks, &iter, callback); info->callback = HashTableIteratorGetKey(&context->callbacks, &iter); - info->id = mScriptListSize(list->value.list); - mScriptValueWrap(fn, mScriptListAppend(list->value.list)); + info->oneshot = oneshot; + if (fn->type->base == mSCRIPT_TYPE_WRAPPER) { + fn = mScriptValueUnwrap(fn); + } + info->fn = fn; + mScriptValueRef(fn); while (true) { uint32_t id = context->nextCallbackId; ++context->nextCallbackId; @@ -245,8 +320,19 @@ uint32_t mScriptContextAddCallback(struct mScriptContext* context, const char* c continue; } TableInsert(&context->callbackId, id, info); - return id; + info->id = id; + break; } + TableInsert(table, info->id, info); + return info->id; +} + +uint32_t mScriptContextAddCallback(struct mScriptContext* context, const char* callback, struct mScriptValue* fn) { + return mScriptContextAddCallbackInternal(context, callback, fn, false); +} + +uint32_t mScriptContextAddOneshot(struct mScriptContext* context, const char* callback, struct mScriptValue* fn) { + return mScriptContextAddCallbackInternal(context, callback, fn, true); } void mScriptContextRemoveCallback(struct mScriptContext* context, uint32_t cbid) { @@ -254,16 +340,13 @@ void mScriptContextRemoveCallback(struct mScriptContext* context, uint32_t cbid) if (!info) { return; } - struct mScriptValue* list = HashTableLookup(&context->callbacks, info->callback); - if (!list) { + struct Table* table = HashTableLookup(&context->callbacks, info->callback); + if (!table) { return; } - if (info->id >= mScriptListSize(list->value.list)) { - return; - } - struct mScriptValue* fn = mScriptValueUnwrap(mScriptListGetPointer(list->value.list, info->id)); - mScriptValueDeref(fn); - mScriptListGetPointer(list->value.list, info->id)->type = NULL; + mScriptValueDeref(info->fn); + TableRemove(table, cbid); + TableRemove(&context->callbackId, cbid); } void mScriptContextExportConstants(struct mScriptContext* context, const char* nspace, struct mScriptKVPair* constants) { @@ -311,6 +394,7 @@ void mScriptEngineExportDocNamespace(struct mScriptEngineContext* ctx, const cha struct mScriptValue* key = mScriptStringCreateFromUTF8(values[i].key); mScriptTableInsert(table, key, values[i].value); mScriptValueDeref(key); + mScriptValueDeref(values[i].value); } HashTableInsert(&ctx->docroot, nspace, table); } @@ -350,6 +434,48 @@ bool mScriptContextLoadFile(struct mScriptContext* context, const char* path) { return ret; } +struct mScriptContext* mScriptActiveContext(void) { + return ThreadLocalGetValue(_threadContext); +} + +bool mScriptContextActivate(struct mScriptContext* context) { + struct mScriptContext* threadContext = ThreadLocalGetValue(_threadContext); + if (threadContext && threadContext != context) { + return false; + } + if (!threadContext && context->threadDepth) { + return false; + } + ++context->threadDepth; + if (!threadContext) { + ThreadLocalSetKey(_threadContext, context); + } + return true; +} + +void mScriptContextDeactivate(struct mScriptContext* context) { +#ifndef NDEBUG + struct mScriptContext* threadContext = ThreadLocalGetValue(_threadContext); + if (threadContext != context) { + abort(); + } +#endif + + --context->threadDepth; + if (!context->threadDepth) { + ThreadLocalSetKey(_threadContext, NULL); + } +} + +bool mScriptContextInvoke(struct mScriptContext* context, const struct mScriptValue* fn, struct mScriptFrame* frame) { + if (!mScriptContextActivate(context)) { + return false; + } + bool res = mScriptInvoke(fn, frame); + mScriptContextDeactivate(context); + return res; +} + bool mScriptInvoke(const struct mScriptValue* val, struct mScriptFrame* frame) { if (val->type->base != mSCRIPT_TYPE_FUNCTION) { return false; diff --git a/src/script/engines/lua.c b/src/script/engines/lua.c index 37327ee54..32ed0d13e 100644 --- a/src/script/engines/lua.c +++ b/src/script/engines/lua.c @@ -36,8 +36,11 @@ static const char* _luaGetError(struct mScriptEngineContext*); static bool _luaCall(struct mScriptFrame*, void* context); +static void _freeFrame(struct mScriptList* frame); +static void _autofreeFrame(struct mScriptContext* context, struct mScriptList* frame); + struct mScriptEngineContextLua; -static bool _luaPushFrame(struct mScriptEngineContextLua*, struct mScriptList*, bool internal); +static bool _luaPushFrame(struct mScriptEngineContextLua*, struct mScriptList*); static bool _luaPopFrame(struct mScriptEngineContextLua*, struct mScriptList*); static bool _luaInvoke(struct mScriptEngineContextLua*, struct mScriptFrame*); @@ -57,6 +60,7 @@ static int _luaGetList(lua_State* lua); static int _luaLenList(lua_State* lua); static int _luaRequireShim(lua_State* lua); +static int _luaPrintShim(lua_State* lua); static const char* _socketLuaSource = "socket = {\n" @@ -98,7 +102,7 @@ static const char* _socketLuaSource = " local cbid = self._nextCallback\n" " self._nextCallback = cbid + 1\n" " self._callbacks[event][cbid] = callback\n" - " return id\n" + " return cbid\n" " end,\n" " remove = function(self, cbid)\n" " for _, group in pairs(self._callbacks) do\n" @@ -131,7 +135,7 @@ static const char* _socketLuaSource = " end,\n" " connect = function(self, address, port)\n" " local status = self._s:connect(address, port)\n" - " return socket._wrap(status)\n" + " return self:_hook(status)\n" " end,\n" " listen = function(self, backlog)\n" " local status = self._s:listen(backlog or 1)\n" @@ -411,6 +415,14 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS lua_getglobal(luaContext->lua, "require"); luaContext->require = luaL_ref(luaContext->lua, LUA_REGISTRYINDEX); + lua_pushliteral(luaContext->lua, "log"); + lua_pushcclosure(luaContext->lua, _luaPrintShim, 1); + lua_setglobal(luaContext->lua, "print"); + + lua_pushliteral(luaContext->lua, "warn"); + lua_pushcclosure(luaContext->lua, _luaPrintShim, 1); + lua_setglobal(luaContext->lua, "warn"); + HashTableInit(&luaContext->d.docroot, 0, (void (*)(void*)) mScriptValueDeref); int status = luaL_dostring(luaContext->lua, _socketLuaSource); @@ -424,6 +436,7 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS lua_getfield(luaContext->lua, -1, "ERRORS"); for (i = 0; i < _mScriptSocketNumErrors; i++) { const struct _mScriptSocketError* err = &_mScriptSocketErrors[i]; + lua_pushinteger(luaContext->lua, err->err); if (err->message) { lua_pushstring(luaContext->lua, err->message); struct mScriptValue* key = mScriptValueAlloc(mSCRIPT_TYPE_MS_S32); @@ -435,7 +448,7 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS } else { lua_pushnil(luaContext->lua); } - lua_seti(luaContext->lua, -2, err->err); + lua_settable(luaContext->lua, -3); } lua_pop(luaContext->lua, 2); @@ -446,7 +459,6 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS mSCRIPT_KV_PAIR(connect, mSCRIPT_VALUE_DOC_FUNCTION(socket_connect)), mSCRIPT_KV_SENTINEL }); - mScriptValueDeref(errors); mScriptEngineSetDocstring(&luaContext->d, "socket", "A basic TCP socket library"); mScriptEngineSetDocstring(&luaContext->d, "socket.ERRORS", "Error strings corresponding to the C.SOCKERR error codes, indexed both by name and by value"); @@ -461,6 +473,16 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS "the connection either succeeds or fails"); } + mScriptEngineExportDocNamespace(&luaContext->d, "script", (struct mScriptKVPair[]) { + mSCRIPT_KV_PAIR(dir, mScriptStringCreateFromASCII("/")), + mSCRIPT_KV_PAIR(path, mScriptStringCreateFromASCII("/lua")), + mSCRIPT_KV_SENTINEL + }); + + mScriptEngineSetDocstring(&luaContext->d, "script", "Information about the currently loaded script"); + mScriptEngineSetDocstring(&luaContext->d, "script.dir", "The path to the directory containing the script"); + mScriptEngineSetDocstring(&luaContext->d, "script.path", "The path of the current script file"); + return &luaContext->d; } @@ -520,6 +542,8 @@ struct mScriptValue* _luaRootScope(struct mScriptEngineContext* ctx) { lua_pop(luaContext->lua, 1); key = _luaCoerce(luaContext, false); mScriptValueWrap(key, mScriptListAppend(list->value.list)); + mScriptValueRef(key); + mScriptContextFillPool(luaContext->d.context, key); } lua_pop(luaContext->lua, 1); @@ -538,11 +562,13 @@ struct mScriptValue* _luaCoerceFunction(struct mScriptEngineContextLua* luaConte return value; } -struct mScriptValue* _luaCoerceTable(struct mScriptEngineContextLua* luaContext) { +struct mScriptValue* _luaCoerceTable(struct mScriptEngineContextLua* luaContext, struct Table* markedObjects) { struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE); bool isList = true; lua_pushnil(luaContext->lua); + + const void* tablePointer; while (lua_next(luaContext->lua, -2) != 0) { struct mScriptValue* value = NULL; int type = lua_type(luaContext->lua, -1); @@ -553,14 +579,20 @@ struct mScriptValue* _luaCoerceTable(struct mScriptEngineContextLua* luaContext) case LUA_TFUNCTION: value = _luaCoerce(luaContext, true); break; + case LUA_TTABLE: + tablePointer = lua_topointer(luaContext->lua, -1); + // Ensure this table doesn't contain any cycles + if (!HashTableLookupBinary(markedObjects, &tablePointer, sizeof(tablePointer))) { + HashTableInsertBinary(markedObjects, &tablePointer, sizeof(tablePointer), (void*) tablePointer); + value = _luaCoerceTable(luaContext, markedObjects); + } default: - // Don't let values be something that could contain themselves break; } if (!value) { - lua_pop(luaContext->lua, 3); + lua_pop(luaContext->lua, type == LUA_TTABLE ? 2 : 3); mScriptValueDeref(table); - return false; + return NULL; } struct mScriptValue* key = NULL; @@ -606,11 +638,17 @@ struct mScriptValue* _luaCoerceTable(struct mScriptEngineContextLua* luaContext) } if (i != len + 1) { mScriptValueDeref(list); - mScriptContextFillPool(luaContext->d.context, table); return table; } + for (i = 0; i < mScriptListSize(list->value.list); ++i) { + struct mScriptValue* value = mScriptListGetPointer(list->value.list, i); + if (value->type->base != mSCRIPT_TYPE_WRAPPER) { + continue; + } + value = mScriptValueUnwrap(value); + mScriptValueRef(value); + } mScriptValueDeref(table); - mScriptContextFillPool(luaContext->d.context, list); return list; } @@ -622,6 +660,7 @@ struct mScriptValue* _luaCoerce(struct mScriptEngineContextLua* luaContext, bool size_t size; const void* buffer; + struct Table markedObjects; struct mScriptValue* value = NULL; switch (lua_type(luaContext->lua, -1)) { case LUA_TNIL: @@ -645,7 +684,6 @@ struct mScriptValue* _luaCoerce(struct mScriptEngineContextLua* luaContext, bool case LUA_TSTRING: buffer = lua_tolstring(luaContext->lua, -1, &size); value = mScriptStringCreateFromBytes(buffer, size); - mScriptContextFillPool(luaContext->d.context, value); break; case LUA_TFUNCTION: // This function pops the value internally via luaL_ref @@ -658,19 +696,36 @@ struct mScriptValue* _luaCoerce(struct mScriptEngineContextLua* luaContext, bool if (!pop) { break; } - return _luaCoerceTable(luaContext); + HashTableInit(&markedObjects, 0, NULL); + value = _luaCoerceTable(luaContext, &markedObjects); + HashTableDeinit(&markedObjects); + return value; case LUA_TUSERDATA: if (!lua_getmetatable(luaContext->lua, -1)) { break; } luaL_getmetatable(luaContext->lua, "mSTStruct"); if (!lua_rawequal(luaContext->lua, -1, -2)) { - lua_pop(luaContext->lua, 2); - break; + lua_pop(luaContext->lua, 1); + luaL_getmetatable(luaContext->lua, "mSTList"); + if (!lua_rawequal(luaContext->lua, -1, -2)) { + lua_pop(luaContext->lua, 1); + luaL_getmetatable(luaContext->lua, "mSTTable"); + if (!lua_rawequal(luaContext->lua, -1, -2)) { + lua_pop(luaContext->lua, 2); + break; + } + } } lua_pop(luaContext->lua, 2); value = lua_touserdata(luaContext->lua, -1); value = mScriptContextAccessWeakref(luaContext->d.context, value); + if (value->type->base == mSCRIPT_TYPE_WRAPPER) { + value = mScriptValueUnwrap(value); + } + if (value) { + mScriptValueRef(value); + } break; } if (pop) { @@ -692,6 +747,32 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v lua_pushnil(luaContext->lua); return true; } + mScriptContextFillPool(luaContext->d.context, value); + } + struct mScriptValue derefPtr; + if (value->type->base == mSCRIPT_TYPE_OPAQUE) { + if (!value->type->details.type) { + return false; + } + mScriptValueFollowPointer(value, &derefPtr); + switch (derefPtr.type->base) { + case mSCRIPT_TYPE_VOID: + case mSCRIPT_TYPE_SINT: + case mSCRIPT_TYPE_UINT: + case mSCRIPT_TYPE_FLOAT: + value = &derefPtr; + break; + case mSCRIPT_TYPE_OBJECT: + value = mScriptValueAlloc(derefPtr.type); + value->value.opaque = derefPtr.value.opaque; + weakref = mScriptContextSetWeakref(luaContext->d.context, value); + needsWeakref = true; + mScriptContextDisownWeakref(luaContext->d.context, weakref); + mScriptValueDeref(value); + break; + default: + return false; + } } if (value->type == mSCRIPT_TYPE_MS_WEAKREF) { weakref = value->value.u32; @@ -738,13 +819,26 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v } break; case mSCRIPT_TYPE_STRING: - lua_pushlstring(luaContext->lua, value->value.string->buffer, value->value.string->size); + if (!value->value.string) { + lua_pushnil(luaContext->lua); + break; + } + if (value->type == mSCRIPT_TYPE_MS_STR) { + lua_pushlstring(luaContext->lua, value->value.string->buffer, value->value.string->size); + break; + } + if (value->type == mSCRIPT_TYPE_MS_CHARP) { + lua_pushstring(luaContext->lua, value->value.copaque); + break; + } + ok = false; break; case mSCRIPT_TYPE_LIST: newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue)); if (needsWeakref) { *newValue = mSCRIPT_MAKE(WEAKREF, weakref); } else { + mScriptValueRef(value); mScriptValueWrap(value, newValue); } lua_getfield(luaContext->lua, LUA_REGISTRYINDEX, "mSTList"); @@ -755,6 +849,7 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v if (needsWeakref) { *newValue = mSCRIPT_MAKE(WEAKREF, weakref); } else { + mScriptValueRef(value); mScriptValueWrap(value, newValue); } lua_getfield(luaContext->lua, LUA_REGISTRYINDEX, "mSTTable"); @@ -766,13 +861,17 @@ bool _luaWrap(struct mScriptEngineContextLua* luaContext, struct mScriptValue* v newValue->refs = mSCRIPT_VALUE_UNREF; newValue->type->alloc(newValue); lua_pushcclosure(luaContext->lua, _luaThunk, 1); - mScriptValueDeref(value); break; case mSCRIPT_TYPE_OBJECT: + if (!value->value.opaque) { + lua_pushnil(luaContext->lua); + break; + } newValue = lua_newuserdata(luaContext->lua, sizeof(*newValue)); if (needsWeakref) { *newValue = mSCRIPT_MAKE(WEAKREF, weakref); } else { + mScriptValueRef(value); mScriptValueWrap(value, newValue); } lua_getfield(luaContext->lua, LUA_REGISTRYINDEX, "mSTStruct"); @@ -803,6 +902,30 @@ static const char* _reader(lua_State* lua, void* context, size_t* size) { return reader->block; } +void _luaError(struct mScriptEngineContextLua* luaContext) { + struct mScriptValue* console = mScriptContextGetGlobal(luaContext->d.context, "console"); + struct mScriptValue error = {0}; + bool ok = false; + if (console) { + ok = mScriptObjectGet(console, "error", &error); + } + if (ok) { + struct mScriptFrame frame; + mScriptFrameInit(&frame); + struct mScriptValue* this = mScriptListAppend(&frame.arguments); + this->type = console->type; + this->refs = mSCRIPT_VALUE_UNREF; + this->flags = 0; + this->value.opaque = console->value.opaque; + mSCRIPT_PUSH(&frame.arguments, CHARP, luaContext->lastError); + ok = mScriptInvoke(&error, &frame); + mScriptFrameDeinit(&frame); + } + if (!ok) { + mLOG(SCRIPT, ERROR, "%s", luaContext->lastError); + } +} + bool _luaLoad(struct mScriptEngineContext* ctx, const char* filename, struct VFile* vf) { struct mScriptEngineContextLua* luaContext = (struct mScriptEngineContextLua*) ctx; struct mScriptEngineLuaReader data = { @@ -813,7 +936,9 @@ bool _luaLoad(struct mScriptEngineContext* ctx, const char* filename, struct VFi luaContext->lastError = NULL; } char name[PATH_MAX + 1]; - char dirname[PATH_MAX] = {0}; + char dirname[PATH_MAX]; + name[0] = '\0'; + dirname[0] = '\0'; if (filename) { if (*filename == '*') { snprintf(name, sizeof(name), "=%s", filename + 1); @@ -828,7 +953,11 @@ bool _luaLoad(struct mScriptEngineContext* ctx, const char* filename, struct VFi lastSlash = lastBackslash; } if (lastSlash) { - strncpy(dirname, filename, lastSlash - filename); + size_t len = lastSlash - filename + 1; + if (sizeof(dirname) < len) { + len = sizeof(dirname); + } + strlcpy(dirname, filename, len); } snprintf(name, sizeof(name), "@%s", filename); } @@ -841,19 +970,49 @@ bool _luaLoad(struct mScriptEngineContext* ctx, const char* filename, struct VFi #endif switch (ret) { case LUA_OK: + // Create new _ENV + lua_newtable(luaContext->lua); + + // Make the old _ENV the __index in the metatable + lua_newtable(luaContext->lua); + lua_pushliteral(luaContext->lua, "__index"); + lua_getupvalue(luaContext->lua, -4, 1); + lua_rawset(luaContext->lua, -3); + + lua_pushliteral(luaContext->lua, "__newindex"); + lua_getupvalue(luaContext->lua, -4, 1); + lua_rawset(luaContext->lua, -3); + + lua_setmetatable(luaContext->lua, -2); + + lua_pushliteral(luaContext->lua, "script"); + lua_newtable(luaContext->lua); + if (dirname[0]) { - lua_getupvalue(luaContext->lua, -1, 1); lua_pushliteral(luaContext->lua, "require"); lua_pushstring(luaContext->lua, dirname); lua_pushcclosure(luaContext->lua, _luaRequireShim, 1); + lua_rawset(luaContext->lua, -5); + + lua_pushliteral(luaContext->lua, "dir"); + lua_pushstring(luaContext->lua, dirname); lua_rawset(luaContext->lua, -3); - lua_pop(luaContext->lua, 1); } + + if (name[0] == '@') { + lua_pushliteral(luaContext->lua, "path"); + lua_pushstring(luaContext->lua, &name[1]); + lua_rawset(luaContext->lua, -3); + } + + lua_rawset(luaContext->lua, -3); + lua_setupvalue(luaContext->lua, -2, 1); luaContext->func = luaL_ref(luaContext->lua, LUA_REGISTRYINDEX); return true; case LUA_ERRSYNTAX: luaContext->lastError = strdup(lua_tostring(luaContext->lua, -1)); lua_pop(luaContext->lua, 1); + _luaError(luaContext); break; default: break; @@ -873,16 +1032,12 @@ const char* _luaGetError(struct mScriptEngineContext* context) { return luaContext->lastError; } -bool _luaPushFrame(struct mScriptEngineContextLua* luaContext, struct mScriptList* frame, bool internal) { +bool _luaPushFrame(struct mScriptEngineContextLua* luaContext, struct mScriptList* frame) { bool ok = true; if (frame) { size_t i; for (i = 0; i < mScriptListSize(frame); ++i) { struct mScriptValue* value = mScriptListGetPointer(frame, i); - if (internal && value->type->base == mSCRIPT_TYPE_WRAPPER) { - value = mScriptValueUnwrap(value); - mScriptContextFillPool(luaContext->d.context, value); - } if (!_luaWrap(luaContext, value)) { ok = false; break; @@ -906,8 +1061,11 @@ bool _luaPopFrame(struct mScriptEngineContextLua* luaContext, struct mScriptList ok = false; break; } - mScriptValueWrap(value, mScriptListAppend(frame)); - mScriptValueDeref(value); + struct mScriptValue* tail = mScriptListAppend(frame); + mScriptValueWrap(value, tail); + if (tail->type == value->type) { + mScriptValueDeref(value); + } } if (count > i) { lua_pop(luaContext->lua, count - i); @@ -934,6 +1092,26 @@ bool _luaCall(struct mScriptFrame* frame, void* context) { return true; } +void _freeFrame(struct mScriptList* frame) { + size_t i; + for (i = 0; i < mScriptListSize(frame); ++i) { + struct mScriptValue* val = mScriptValueUnwrap(mScriptListGetPointer(frame, i)); + if (val) { + mScriptValueDeref(val); + } + } +} + +void _autofreeFrame(struct mScriptContext* context, struct mScriptList* frame) { + size_t i; + for (i = 0; i < mScriptListSize(frame); ++i) { + struct mScriptValue* val = mScriptValueUnwrap(mScriptListGetPointer(frame, i)); + if (val) { + mScriptContextFillPool(context, val); + } + } +} + bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame* frame) { int nargs = 0; if (frame) { @@ -945,7 +1123,12 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame* luaContext->lastError = NULL; } - if (frame && !_luaPushFrame(luaContext, &frame->arguments, false)) { + if (!mScriptContextActivate(luaContext->d.context)) { + return false; + } + + if (frame && !_luaPushFrame(luaContext, &frame->arguments)) { + mScriptContextDeactivate(luaContext->d.context); return false; } @@ -960,7 +1143,10 @@ bool _luaInvoke(struct mScriptEngineContextLua* luaContext, struct mScriptFrame* if (ret == LUA_ERRRUN) { luaContext->lastError = strdup(lua_tostring(luaContext->lua, -1)); lua_pop(luaContext->lua, 1); + + _luaError(luaContext); } + mScriptContextDeactivate(luaContext->d.context); if (ret) { return false; } @@ -1010,6 +1196,7 @@ int _luaThunk(lua_State* lua) { struct mScriptFrame frame; mScriptFrameInit(&frame); if (!_luaPopFrame(luaContext, &frame.arguments)) { + _freeFrame(&frame.arguments); mScriptContextDrainPool(luaContext->d.context); mScriptFrameDeinit(&frame); luaL_traceback(lua, lua, "Error calling function (translating arguments into runtime)", 1); @@ -1017,19 +1204,21 @@ int _luaThunk(lua_State* lua) { } struct mScriptValue* fn = lua_touserdata(lua, lua_upvalueindex(1)); - if (!fn || !mScriptInvoke(fn, &frame)) { + _autofreeFrame(luaContext->d.context, &frame.arguments); + if (!fn || !mScriptContextInvoke(luaContext->d.context, fn, &frame)) { + mScriptContextDrainPool(luaContext->d.context); mScriptFrameDeinit(&frame); luaL_traceback(lua, lua, "Error calling function (invoking failed)", 1); return lua_error(lua); } - if (!_luaPushFrame(luaContext, &frame.returnValues, true)) { - mScriptFrameDeinit(&frame); + bool ok = _luaPushFrame(luaContext, &frame.returnValues); + mScriptContextDrainPool(luaContext->d.context); + mScriptFrameDeinit(&frame); + if (!ok) { luaL_traceback(lua, lua, "Error calling function (translating return values from runtime)", 1); return lua_error(lua); } - mScriptContextDrainPool(luaContext->d.context); - mScriptFrameDeinit(&frame); return lua_gettop(luaContext->lua); } @@ -1084,19 +1273,22 @@ int _luaSetObject(lua_State* lua) { strlcpy(key, keyPtr, sizeof(key)); lua_pop(lua, 2); - obj = mScriptContextAccessWeakref(luaContext->d.context, obj); - if (!obj) { - luaL_traceback(lua, lua, "Invalid object", 1); - return lua_error(lua); - } - if (!val) { luaL_traceback(lua, lua, "Error translating value to runtime", 1); return lua_error(lua); } + obj = mScriptContextAccessWeakref(luaContext->d.context, obj); + if (!obj) { + mScriptValueDeref(val); + mScriptContextDrainPool(luaContext->d.context); + luaL_traceback(lua, lua, "Invalid object", 1); + return lua_error(lua); + } + if (!mScriptObjectSet(obj, key, val)) { mScriptValueDeref(val); + mScriptContextDrainPool(luaContext->d.context); char error[MAX_KEY_SIZE + 16]; snprintf(error, sizeof(error), "Invalid key '%s'", key); luaL_traceback(lua, lua, "Invalid key", 1); @@ -1141,7 +1333,10 @@ int _luaGetTable(lua_State* lua) { lua_pop(lua, 2); obj = mScriptContextAccessWeakref(luaContext->d.context, obj); - if (!obj) { + if (obj->type->base == mSCRIPT_TYPE_WRAPPER) { + obj = mScriptValueUnwrap(obj); + } + if (!obj || obj->type != mSCRIPT_TYPE_MS_TABLE) { luaL_traceback(lua, lua, "Invalid table", 1); return lua_error(lua); } @@ -1173,7 +1368,10 @@ int _luaLenTable(lua_State* lua) { lua_pop(lua, 1); obj = mScriptContextAccessWeakref(luaContext->d.context, obj); - if (!obj) { + if (obj->type->base == mSCRIPT_TYPE_WRAPPER) { + obj = mScriptValueUnwrap(obj); + } + if (!obj || obj->type != mSCRIPT_TYPE_MS_TABLE) { luaL_traceback(lua, lua, "Invalid table", 1); return lua_error(lua); } @@ -1209,7 +1407,10 @@ static int _luaNextTable(lua_State* lua) { lua_pop(lua, 2); table = mScriptContextAccessWeakref(luaContext->d.context, table); - if (!table) { + if (table->type->base == mSCRIPT_TYPE_WRAPPER) { + table = mScriptValueUnwrap(table); + } + if (!table || table->type != mSCRIPT_TYPE_MS_TABLE) { luaL_traceback(lua, lua, "Invalid table", 1); return lua_error(lua); } @@ -1369,3 +1570,37 @@ static int _luaRequireShim(lua_State* lua) { int newtop = lua_gettop(luaContext->lua); return newtop - oldtop + 1; } + +static int _luaPrintShim(lua_State* lua) { + int n = lua_gettop(lua); + + lua_getglobal(lua, "console"); + lua_insert(lua, 1); + + // The first upvalue is either "log" or "warn" + lua_getglobal(lua, "console"); + lua_pushvalue(lua, lua_upvalueindex(1)); + lua_gettable(lua, -2); + + lua_insert(lua, 1); + lua_pop(lua, 1); + + // TODO when console:log is variadic and stringifies by itself: + // lua_call(lua, n + 1, 0); + + // Until then, stringify and concatenate: + for (int i = 0; i < n; i++) { + luaL_tolstring(lua, i * 2 + 3, NULL); + lua_replace(lua, i * 2 + 3); + if (i == 0) { + lua_pushliteral(lua, ""); + } else { + lua_pushliteral(lua, "\t"); + } + lua_insert(lua, i * 2 + 3); + } + n = n * 2 - 1; + lua_concat(lua, n + 1); + lua_call(lua, 2, 0); + return 0; +} diff --git a/src/script/image.c b/src/script/image.c new file mode 100644 index 000000000..f056c7d49 --- /dev/null +++ b/src/script/image.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2013-2023 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 + +struct mScriptPainter { + struct mPainter painter; + struct mScriptValue* image; + struct mPainter* ppainter; // XXX: Figure out how to not need this without breaking the type system +}; + +mSCRIPT_DECLARE_STRUCT(mPainter); +mSCRIPT_DECLARE_STRUCT(mScriptPainter); + +static struct mScriptValue* _mImageNew(unsigned width, unsigned height) { + // For various reasons, it's probably a good idea to limit the maximum image size scripts can make + if (width >= 10000 || height >= 10000) { + return NULL; + } + struct mImage* image = mImageCreate(width, height, mCOLOR_ABGR8); + if (!image) { + return NULL; + } + struct mScriptValue* result = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mImage)); + result->value.opaque = image; + result->flags = mSCRIPT_VALUE_FLAG_DEINIT; + return result; +} + +static struct mScriptValue* _mImageLoad(const char* path) { + struct mImage* image = mImageLoad(path); + if (!image) { + return NULL; + } + struct mScriptValue* result = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mImage)); + result->value.opaque = image; + result->flags = mSCRIPT_VALUE_FLAG_DEINIT; + return result; +} + +static struct mScriptValue* _mImageNewPainter(struct mScriptValue* image) { + mScriptValueRef(image); + struct mScriptPainter* painter = malloc(sizeof(*painter)); + mPainterInit(&painter->painter, image->value.opaque); + painter->image = image; + painter->ppainter = &painter->painter; + struct mScriptValue* result = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptPainter)); + result->value.opaque = painter; + result->flags = mSCRIPT_VALUE_FLAG_DEINIT; + return result; +} + +mSCRIPT_DECLARE_STRUCT_C_METHOD(mImage, U32, getPixel, mImageGetPixel, 2, U32, x, U32, y); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mImage, setPixel, mImageSetPixel, 3, U32, x, U32, y, U32, color); +mSCRIPT_DECLARE_STRUCT_C_METHOD_WITH_DEFAULTS(mImage, BOOL, save, mImageSave, 2, CHARP, path, CHARP, format); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mImage, _deinit, mImageDestroy, 0); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mImage, drawImageOpaque, mImageBlit, 3, CS(mImage), image, U32, x, U32, y); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD_WITH_DEFAULTS(mImage, drawImage, mImageCompositeWithAlpha, 4, CS(mImage), image, U32, x, U32, y, F32, alpha); + +mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mImage, save) + mSCRIPT_NO_DEFAULT, + mSCRIPT_CHARP("PNG") +mSCRIPT_DEFINE_DEFAULTS_END; + +mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mImage, drawImage) + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_NO_DEFAULT, + mSCRIPT_F32(1.0f) +mSCRIPT_DEFINE_DEFAULTS_END; + +mSCRIPT_DEFINE_STRUCT(mImage) + mSCRIPT_DEFINE_CLASS_DOCSTRING( + "A single, static image." + ) + mSCRIPT_DEFINE_STRUCT_DEINIT(mImage) + mSCRIPT_DEFINE_DOCSTRING("Save the image to a file. Currently, only `PNG` format is supported") + mSCRIPT_DEFINE_STRUCT_METHOD(mImage, save) + mSCRIPT_DEFINE_DOCSTRING("Get the ARGB value of the pixel at a given coordinate") + mSCRIPT_DEFINE_STRUCT_METHOD(mImage, getPixel) + mSCRIPT_DEFINE_DOCSTRING("Set the ARGB value of the pixel at a given coordinate") + mSCRIPT_DEFINE_STRUCT_METHOD(mImage, setPixel) + mSCRIPT_DEFINE_DOCSTRING("Draw another image onto this image without any alpha blending, overwriting what was already there") + mSCRIPT_DEFINE_STRUCT_METHOD(mImage, drawImageOpaque) + mSCRIPT_DEFINE_DOCSTRING("Draw another image onto this image with alpha blending as needed, optionally specifying a coefficient for adjusting the opacity") + mSCRIPT_DEFINE_STRUCT_METHOD(mImage, drawImage) + mSCRIPT_DEFINE_DOCSTRING("The width of the image, in pixels") + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(mImage, U32, width) + mSCRIPT_DEFINE_DOCSTRING("The height of the image, in pixels") + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(mImage, U32, height) +mSCRIPT_DEFINE_END; + +mSCRIPT_BIND_FUNCTION(mImageNew_Binding, W(mImage), _mImageNew, 2, U32, width, U32, height); +mSCRIPT_BIND_FUNCTION(mImageLoad_Binding, W(mImage), _mImageLoad, 1, CHARP, path); +mSCRIPT_BIND_FUNCTION(mImageNewPainter_Binding, W(mScriptPainter), _mImageNewPainter, 1, W(mImage), image); + +void _mPainterSetBlend(struct mPainter* painter, bool enable) { + painter->blend = enable; +} + +void _mPainterSetFill(struct mPainter* painter, bool enable) { + painter->fill = enable; +} + +void _mPainterSetFillColor(struct mPainter* painter, uint32_t color) { + painter->fillColor = color; +} + +void _mPainterSetStrokeWidth(struct mPainter* painter, uint32_t width) { + painter->strokeWidth = width; +} + +void _mPainterSetStrokeColor(struct mPainter* painter, uint32_t color) { + painter->strokeColor = color; +} + +static struct mScriptValue* _mScriptPainterGet(struct mScriptPainter* painter, const char* name) { + struct mScriptValue val; + struct mScriptValue realPainter = mSCRIPT_MAKE(S(mPainter), &painter->painter); + if (!mScriptObjectGet(&realPainter, name, &val)) { + return &mScriptValueNull; + } + + struct mScriptValue* ret = malloc(sizeof(*ret)); + memcpy(ret, &val, sizeof(*ret)); + ret->refs = 1; + return ret; +} + +void _mScriptPainterDeinit(struct mScriptPainter* painter) { + mScriptValueDeref(painter->image); +} + +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, setBlend, _mPainterSetBlend, 1, BOOL, enable); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, setFill, _mPainterSetFill, 1, BOOL, enable); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, setFillColor, _mPainterSetFillColor, 1, U32, color); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, setStrokeWidth, _mPainterSetStrokeWidth, 1, U32, width); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, setStrokeColor, _mPainterSetStrokeColor, 1, U32, color); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, drawRectangle, mPainterDrawRectangle, 4, S32, x, S32, y, S32, width, S32, height); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, drawLine, mPainterDrawLine, 4, S32, x1, S32, y1, S32, x2, S32, y2); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mPainter, drawCircle, mPainterDrawCircle, 3, S32, x, S32, y, S32, diameter); + +mSCRIPT_DEFINE_STRUCT(mPainter) + mSCRIPT_DEFINE_CLASS_DOCSTRING( + "A stateful object useful for performing drawing operations on an struct::mImage." + ) + mSCRIPT_DEFINE_DOCSTRING("Set whether or not alpha blending should be enabled when drawing") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, setBlend) + mSCRIPT_DEFINE_DOCSTRING("Set whether or not the fill color should be applied when drawing") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, setFill) + mSCRIPT_DEFINE_DOCSTRING("Set the fill color to be used when drawing") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, setFillColor) + mSCRIPT_DEFINE_DOCSTRING("Set the stroke width to be used when drawing, or 0 to disable") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, setStrokeWidth) + mSCRIPT_DEFINE_DOCSTRING("Set the stroke color to be used when drawing") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, setStrokeColor) + mSCRIPT_DEFINE_DOCSTRING("Draw a rectangle with the specified dimensions") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, drawRectangle) + mSCRIPT_DEFINE_DOCSTRING("Draw a line with the specified endpoints") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, drawLine) + mSCRIPT_DEFINE_DOCSTRING("Draw a circle with the specified diameter with the given origin at the top-left corner of the bounding box") + mSCRIPT_DEFINE_STRUCT_METHOD(mPainter, drawCircle) +mSCRIPT_DEFINE_END; + +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptPainter, W(mPainter), _get, _mScriptPainterGet, 1, CHARP, name); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptPainter, _deinit, _mScriptPainterDeinit, 0); + +mSCRIPT_DEFINE_STRUCT(mScriptPainter) + mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptPainter) + mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(mScriptPainter, PS(mPainter), _painter, ppainter) + mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(mScriptPainter) + mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(mScriptPainter, S(mPainter), _painter) +mSCRIPT_DEFINE_END; + +void mScriptContextAttachImage(struct mScriptContext* context) { + mScriptContextExportNamespace(context, "image", (struct mScriptKVPair[]) { + mSCRIPT_KV_PAIR(new, &mImageNew_Binding), + mSCRIPT_KV_PAIR(load, &mImageLoad_Binding), + mSCRIPT_KV_PAIR(newPainter, &mImageNewPainter_Binding), + mSCRIPT_KV_SENTINEL + }); + mScriptContextSetDocstring(context, "image", "Methods for creating struct::mImage and struct::mPainter instances"); + mScriptContextSetDocstring(context, "image.new", "Create a new image with the given dimensions"); + mScriptContextSetDocstring(context, "image.load", "Load an image from a path. Currently, only `PNG` format is supported"); + mScriptContextSetDocstring(context, "image.newPainter", "Create a new painter from an existing image"); +} diff --git a/src/script/input.c b/src/script/input.c new file mode 100644 index 000000000..c103fa82c --- /dev/null +++ b/src/script/input.c @@ -0,0 +1,619 @@ +/* Copyright (c) 2013-2022 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 + +#include +#include +#include + +static const char* eventNames[mSCRIPT_EV_TYPE_MAX] = { + [mSCRIPT_EV_TYPE_KEY] = "key", + [mSCRIPT_EV_TYPE_MOUSE_BUTTON] = "mouseButton", + [mSCRIPT_EV_TYPE_MOUSE_MOVE] = "mouseMove", + [mSCRIPT_EV_TYPE_MOUSE_WHEEL] = "mouseWheel", + [mSCRIPT_EV_TYPE_GAMEPAD_BUTTON] = "gamepadButton", + [mSCRIPT_EV_TYPE_GAMEPAD_HAT] = "gamepadHat", + [mSCRIPT_EV_TYPE_TRIGGER] = "trigger", +}; + +static const struct mScriptType* eventTypes[mSCRIPT_EV_TYPE_MAX] = { + [mSCRIPT_EV_TYPE_KEY] = mSCRIPT_TYPE_MS_S(mScriptKeyEvent), + [mSCRIPT_EV_TYPE_MOUSE_BUTTON] = mSCRIPT_TYPE_MS_S(mScriptMouseButtonEvent), + [mSCRIPT_EV_TYPE_MOUSE_MOVE] = mSCRIPT_TYPE_MS_S(mScriptMouseMoveEvent), + [mSCRIPT_EV_TYPE_MOUSE_WHEEL] = mSCRIPT_TYPE_MS_S(mScriptMouseWheelEvent), + [mSCRIPT_EV_TYPE_GAMEPAD_BUTTON] = mSCRIPT_TYPE_MS_S(mScriptGamepadButtonEvent), + [mSCRIPT_EV_TYPE_GAMEPAD_HAT] = mSCRIPT_TYPE_MS_S(mScriptGamepadHatEvent), +}; + +struct mScriptInputContext { + uint64_t seq; + struct Table activeKeys; + struct mScriptGamepad* activeGamepad; +}; + +static void _mScriptInputDeinit(struct mScriptInputContext*); +static bool _mScriptInputIsKeyActive(const struct mScriptInputContext*, struct mScriptValue*); +static struct mScriptValue* _mScriptInputActiveKeys(const struct mScriptInputContext*); + +mSCRIPT_DECLARE_STRUCT(mScriptInputContext); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptInputContext, _deinit, _mScriptInputDeinit, 0); +mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, BOOL, isKeyActive, _mScriptInputIsKeyActive, 1, WRAPPER, key); +mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, WLIST, activeKeys, _mScriptInputActiveKeys, 0); + +mSCRIPT_DEFINE_STRUCT(mScriptInputContext) + mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext) + mSCRIPT_DEFINE_DOCSTRING("Sequence number of the next event to be emitted") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, U64, seq) + mSCRIPT_DEFINE_DOCSTRING("Check if a given keyboard key is currently held. The input can be either the printable character for a key, the numerical Unicode codepoint, or a special value from C.KEY") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive) + mSCRIPT_DEFINE_DOCSTRING("Get a list of the currently active keys. The values are Unicode codepoints or special key values from C.KEY, not strings, so make sure to convert as needed") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, activeKeys) + mSCRIPT_DEFINE_DOCSTRING("The currently active gamepad, if any") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, PCS(mScriptGamepad), activeGamepad) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptEvent) + mSCRIPT_DEFINE_CLASS_DOCSTRING( + "The base class for all event types. Different events have their own subclasses." + ) + mSCRIPT_DEFINE_DOCSTRING("The type of this event. See C.EV_TYPE for a list of possible types.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptEvent, S32, type) + mSCRIPT_DEFINE_DOCSTRING("Sequence number of this event. This value increases monotinically.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptEvent, U64, seq) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptKeyEvent) + mSCRIPT_DEFINE_CLASS_DOCSTRING("A keyboard key event.") + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_DOCSTRING("The state of the key, represented by a C.INPUT_STATE value") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, U8, state) + mSCRIPT_DEFINE_DOCSTRING("A bitmask of current modifiers, represented by ORed C.KMOD values") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, S16, modifiers) + mSCRIPT_DEFINE_DOCSTRING( + "The relevant key for this event. For most printable characters, this will be the Unicode " + "codepoint of the character. Some special values are present as C.KEY as well." + ) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, S32, key) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptMouseButtonEvent) + mSCRIPT_DEFINE_CLASS_DOCSTRING("A mouse button event.") + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_DOCSTRING("Which mouse this event pertains to. Currently, this will always be 0.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, mouse) + mSCRIPT_DEFINE_DOCSTRING("The state of the button, represented by a C.INPUT_STATE value") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, state) + mSCRIPT_DEFINE_DOCSTRING( + "Which mouse button this event pertains to. Symbolic names for primary (usually left), " + "secondary (usually right), and middle are in C.MOUSE_BUTTON, and further buttons " + "are numeric starting from 3." + ) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, button) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptMouseMoveEvent) + mSCRIPT_DEFINE_CLASS_DOCSTRING("A mouse movement event.") + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_DOCSTRING("Which mouse this event pertains to. Currently, this will always be 0.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, U8, mouse) + mSCRIPT_DEFINE_DOCSTRING( + "The x coordinate of the mouse in the context of game screen pixels. " + "This can be out of bounds of the game screen depending on the size of the window in question." + ) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, S32, x) + mSCRIPT_DEFINE_DOCSTRING( + "The y coordinate of the mouse in the context of game screen pixels. " + "This can be out of bounds of the game screen depending on the size of the window in question." + ) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, S32, y) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptMouseWheelEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_DOCSTRING("Which mouse this event pertains to. Currently, this will always be 0.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, U8, mouse) + mSCRIPT_DEFINE_DOCSTRING("The amount scrolled horizontally") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, S32, x) + mSCRIPT_DEFINE_DOCSTRING("The amount scrolled vertically") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, S32, y) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptGamepadButtonEvent) + mSCRIPT_DEFINE_CLASS_DOCSTRING("A gamepad button event.") + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_DOCSTRING("The state of the button, represented by a C.INPUT_STATE value") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U8, state) + mSCRIPT_DEFINE_DOCSTRING("Which gamepad this event pertains to. Currently, this will always be 0.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U8, pad) + mSCRIPT_DEFINE_DOCSTRING( + "Which button this event pertains to. There is currently no guaranteed button mapping, " + "and it might change between different controllers." + ) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U16, button) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptGamepadHatEvent) + mSCRIPT_DEFINE_CLASS_DOCSTRING("A gamepad POV hat event.") + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_DOCSTRING("Which gamepad this event pertains to. Currently, this will always be 0.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, pad) + mSCRIPT_DEFINE_DOCSTRING("Which hat this event pertains to. For most gamepads this will be 0.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, hat) + mSCRIPT_DEFINE_DOCSTRING("The current direction of the hat. See C.INPUT_DIR for possible values.") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, direction) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptGamepad) + mSCRIPT_DEFINE_DOCSTRING("The human-readable name of this gamepad") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, CHARP, visibleName) + mSCRIPT_DEFINE_DOCSTRING("The internal name of this gamepad, generally unique to the specific type of gamepad") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, CHARP, internalName) + mSCRIPT_DEFINE_DOCSTRING("An indexed list of the current values of each axis") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, axes) + mSCRIPT_DEFINE_DOCSTRING("An indexed list of the current values of each button") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, buttons) + mSCRIPT_DEFINE_DOCSTRING("An indexed list of the current values of POV hat") + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, hats) +mSCRIPT_DEFINE_END; + +void mScriptContextAttachInput(struct mScriptContext* context) { + struct mScriptInputContext* inputContext = calloc(1, sizeof(*inputContext)); + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptInputContext)); + value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; + value->value.opaque = inputContext; + + inputContext->seq = 0; + TableInit(&inputContext->activeKeys, 0, NULL); + + mScriptContextSetGlobal(context, "input", value); + mScriptContextSetDocstring(context, "input", "Singleton instance of struct::mScriptInputContext"); + + mScriptContextExportConstants(context, "EV_TYPE", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, KEY), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_BUTTON), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_MOVE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_WHEEL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, GAMEPAD_BUTTON), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, TRIGGER), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "INPUT_STATE", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, UP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, DOWN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, HELD), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "INPUT_DIR", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTH), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, EAST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTH), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, WEST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, UP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, RIGHT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, DOWN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, LEFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTHEAST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTHWEST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTHEAST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTHWEST), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "KEY", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, BACKSPACE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, TAB), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, ENTER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, ESCAPE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, DELETE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F1), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F2), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F3), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F4), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F5), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F6), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F7), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F8), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F9), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F10), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F11), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F12), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F13), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F14), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F15), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F16), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F17), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F18), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F19), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F20), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F21), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F22), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F23), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, F24), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, UP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RIGHT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, DOWN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LEFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, PAGE_UP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, PAGE_DOWN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, HOME), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, END), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, INSERT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, BREAK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, CLEAR), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, PRINT_SCREEN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SYSRQ), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, MENU), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, HELP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LSHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RSHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LCONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RCONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, CONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, ALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, LSUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, RSUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, CAPS_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, NUM_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, SCROLL_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_0), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_1), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_2), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_3), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_4), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_5), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_6), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_7), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_8), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_9), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_PLUS), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_MINUS), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_MULTIPLY), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_DIVIDE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_COMMA), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_POINT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KEY, KP_ENTER), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "KMOD", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LSHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RSHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LCONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RCONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, CONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, ALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LSUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RSUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, CAPS_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, NUM_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SCROLL_LOCK), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "MOUSE_BUTTON", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_MOUSE_BUTTON, PRIMARY), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_MOUSE_BUTTON, SECONDARY), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_MOUSE_BUTTON, MIDDLE), + mSCRIPT_KV_SENTINEL + }); +} + +void _mScriptInputDeinit(struct mScriptInputContext* context) { + TableDeinit(&context->activeKeys); +} + +bool _mScriptInputIsKeyActive(const struct mScriptInputContext* context, struct mScriptValue* value) { + uint32_t key; + struct mScriptValue intValue; + size_t length; + const char* strbuf; + + switch (value->type->base) { + case mSCRIPT_TYPE_SINT: + case mSCRIPT_TYPE_UINT: + case mSCRIPT_TYPE_FLOAT: + if (!mScriptCast(mSCRIPT_TYPE_MS_U32, value, &intValue)) { + return false; + } + key = intValue.value.u32; + break; + case mSCRIPT_TYPE_STRING: + if (value->value.string->length > 1) { + return false; + } + strbuf = value->value.string->buffer; + length = value->value.string->size; + key = utf8Char(&strbuf, &length); + break; + default: + return false; + } + + void* down = TableLookup(&context->activeKeys, key); + return down != NULL; +} + +static struct mScriptValue* _mScriptInputActiveKeys(const struct mScriptInputContext* context) { + struct mScriptValue* list = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST); + struct TableIterator iter; + if (!TableIteratorStart(&context->activeKeys, &iter)) { + return list; + } + do { + uint32_t key = TableIteratorGetKey(&context->activeKeys, &iter); + *mScriptListAppend(list->value.list) = mSCRIPT_MAKE_U32(key); + } while (TableIteratorNext(&context->activeKeys, &iter)); + return list; +} + +static bool _updateKeys(struct mScriptContext* context, struct mScriptKeyEvent* event) { + int offset = 0; + switch (event->state) { + case mSCRIPT_INPUT_STATE_UP: + offset = -1; + break; + case mSCRIPT_INPUT_STATE_DOWN: + offset = 1; + break; + default: + return true; + } + + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return false; + } + struct mScriptInputContext* inputContext = input->value.opaque; + intptr_t value = (intptr_t) TableLookup(&inputContext->activeKeys, event->key); + value += offset; + if (value < 1) { + TableRemove(&inputContext->activeKeys, event->key); + } else { + TableInsert(&inputContext->activeKeys, event->key, (void*) value); + } + if (offset < 0 && value > 0) { + return false; + } + if (offset > 0 && value != 1) { + event->state = mSCRIPT_INPUT_STATE_HELD; + } + return true; +} + +void mScriptContextFireEvent(struct mScriptContext* context, struct mScriptEvent* event) { + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return; + } + struct mScriptInputContext* inputContext = input->value.opaque; + + switch (event->type) { + case mSCRIPT_EV_TYPE_KEY: + if (!_updateKeys(context, (struct mScriptKeyEvent*) event)) { + return; + } + break; + case mSCRIPT_EV_TYPE_NONE: + return; + } + + struct mScriptList args; + mScriptListInit(&args, 1); + struct mScriptValue* value = mScriptListAppend(&args); + value->type = eventTypes[event->type]; + value->refs = mSCRIPT_VALUE_UNREF; + value->flags = 0; + value->value.opaque = event; + event->seq = inputContext->seq; + ++inputContext->seq; + mScriptContextTriggerCallback(context, eventNames[event->type], &args); + mScriptListDeinit(&args); +} + +void mScriptContextClearKeys(struct mScriptContext* context) { + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return; + } + struct mScriptInputContext* inputContext = input->value.opaque; + size_t keyCount = TableSize(&inputContext->activeKeys); + uint32_t* keys = calloc(keyCount, sizeof(uint32_t)); + struct TableIterator iter; + size_t i = 0; + if (!TableIteratorStart(&inputContext->activeKeys, &iter)) { + free(keys); + return; + } + do { + keys[i] = TableIteratorGetKey(&inputContext->activeKeys, &iter); + ++i; + } while (TableIteratorNext(&inputContext->activeKeys, &iter)); + + struct mScriptKeyEvent event = { + .d = { + .type = mSCRIPT_EV_TYPE_KEY + }, + .state = mSCRIPT_INPUT_STATE_UP, + .modifiers = 0 + }; + for (i = 0; i < keyCount; ++i) { + event.key = keys[i]; + intptr_t value = (intptr_t) TableLookup(&inputContext->activeKeys, event.key); + if (value > 1) { + TableInsert(&inputContext->activeKeys, event.key, (void*) 1); + } + mScriptContextFireEvent(context, &event.d); + } + + free(keys); +} + +int mScriptContextGamepadAttach(struct mScriptContext* context, struct mScriptGamepad* pad) { + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return false; + } + struct mScriptInputContext* inputContext = input->value.opaque; + if (inputContext->activeGamepad) { + return -1; + } + inputContext->activeGamepad = pad; + + return 0; +} + +bool mScriptContextGamepadDetach(struct mScriptContext* context, int pad) { + if (pad != 0) { + return false; + } + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return false; + } + struct mScriptInputContext* inputContext = input->value.opaque; + if (!inputContext->activeGamepad) { + return false; + } + inputContext->activeGamepad = NULL; + return true; +} + +struct mScriptGamepad* mScriptContextGamepadLookup(struct mScriptContext* context, int pad) { + if (pad != 0) { + return NULL; + } + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return false; + } + struct mScriptInputContext* inputContext = input->value.opaque; + return inputContext->activeGamepad; +} + +void mScriptGamepadInit(struct mScriptGamepad* gamepad) { + memset(gamepad, 0, sizeof(*gamepad)); + + mScriptListInit(&gamepad->axes, 8); + mScriptListInit(&gamepad->buttons, 1); + mScriptListInit(&gamepad->hats, 1); +} + +void mScriptGamepadDeinit(struct mScriptGamepad* gamepad) { + mScriptListDeinit(&gamepad->axes); + mScriptListDeinit(&gamepad->buttons); + mScriptListDeinit(&gamepad->hats); +} + +void mScriptGamepadSetAxisCount(struct mScriptGamepad* gamepad, unsigned count) { + if (count > UINT8_MAX) { + count = UINT8_MAX; + } + + unsigned oldSize = mScriptListSize(&gamepad->axes); + mScriptListResize(&gamepad->axes, (ssize_t) count - oldSize); + unsigned i; + for (i = oldSize; i < count; ++i) { + *mScriptListGetPointer(&gamepad->axes, i) = mSCRIPT_MAKE_S16(0); + } +} + +void mScriptGamepadSetButtonCount(struct mScriptGamepad* gamepad, unsigned count) { + if (count > UINT16_MAX) { + count = UINT16_MAX; + } + + unsigned oldSize = mScriptListSize(&gamepad->buttons); + mScriptListResize(&gamepad->buttons, (ssize_t) count - oldSize); + unsigned i; + for (i = oldSize; i < count; ++i) { + *mScriptListGetPointer(&gamepad->buttons, i) = mSCRIPT_MAKE_BOOL(false); + } +} + +void mScriptGamepadSetHatCount(struct mScriptGamepad* gamepad, unsigned count) { + if (count > UINT8_MAX) { + count = UINT8_MAX; + } + + unsigned oldSize = mScriptListSize(&gamepad->hats); + mScriptListResize(&gamepad->hats, (ssize_t) count - oldSize); + unsigned i; + for (i = oldSize; i < count; ++i) { + *mScriptListGetPointer(&gamepad->hats, i) = mSCRIPT_MAKE_U8(0); + } +} + +void mScriptGamepadSetAxis(struct mScriptGamepad* gamepad, unsigned id, int16_t value) { + if (id >= mScriptListSize(&gamepad->axes)) { + return; + } + + mScriptListGetPointer(&gamepad->axes, id)->value.s32 = value; +} + +void mScriptGamepadSetButton(struct mScriptGamepad* gamepad, unsigned id, bool down) { + if (id >= mScriptListSize(&gamepad->buttons)) { + return; + } + + mScriptListGetPointer(&gamepad->buttons, id)->value.u32 = down; +} + +void mScriptGamepadSetHat(struct mScriptGamepad* gamepad, unsigned id, int direction) { + if (id >= mScriptListSize(&gamepad->hats)) { + return; + } + + mScriptListGetPointer(&gamepad->hats, id)->value.u32 = direction; +} + +int16_t mScriptGamepadGetAxis(struct mScriptGamepad* gamepad, unsigned id) { + if (id >= mScriptListSize(&gamepad->axes)) { + return 0; + } + + return mScriptListGetPointer(&gamepad->axes, id)->value.s32; +} + +bool mScriptGamepadGetButton(struct mScriptGamepad* gamepad, unsigned id) { + if (id >= mScriptListSize(&gamepad->buttons)) { + return false; + } + + return mScriptListGetPointer(&gamepad->buttons, id)->value.u32; +} + +int mScriptGamepadGetHat(struct mScriptGamepad* gamepad, unsigned id) { + if (id >= mScriptListSize(&gamepad->hats)) { + return mSCRIPT_INPUT_DIR_NONE; + } + + return mScriptListGetPointer(&gamepad->hats, id)->value.u32; +} + +void mScriptContextGetInputTypes(struct Table* types) { + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptEvent)); + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptKeyEvent)); + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptMouseMoveEvent)); + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptMouseButtonEvent)); + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptGamepadButtonEvent)); + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptGamepadHatEvent)); + mScriptTypeAdd(types, mSCRIPT_TYPE_MS_S(mScriptGamepad)); +} diff --git a/src/script/socket.c b/src/script/socket.c index 818c758f6..4684c243e 100644 --- a/src/script/socket.c +++ b/src/script/socket.c @@ -28,7 +28,9 @@ static const struct _mScriptSocketErrorMapping { { ECONNREFUSED, mSCRIPT_SOCKERR_CONNECTION_REFUSED }, { EACCES, mSCRIPT_SOCKERR_DENIED }, { EPERM, mSCRIPT_SOCKERR_DENIED }, +#ifdef ENOTRECOVERABLE { ENOTRECOVERABLE, mSCRIPT_SOCKERR_FAILED }, +#endif { ENETUNREACH, mSCRIPT_SOCKERR_NETWORK_UNREACHABLE }, { ETIMEDOUT, mSCRIPT_SOCKERR_TIMEOUT }, { EINVAL, mSCRIPT_SOCKERR_UNSUPPORTED }, @@ -36,6 +38,7 @@ static const struct _mScriptSocketErrorMapping { #ifndef USE_GETHOSTBYNAME #ifdef _WIN32 { WSATRY_AGAIN, mSCRIPT_SOCKERR_AGAIN }, + { WSAEWOULDBLOCK, mSCRIPT_SOCKERR_AGAIN }, { WSANO_RECOVERY, mSCRIPT_SOCKERR_FAILED }, { WSANO_DATA, mSCRIPT_SOCKERR_NO_DATA }, { WSAHOST_NOT_FOUND, mSCRIPT_SOCKERR_NOT_FOUND }, diff --git a/src/script/stdlib.c b/src/script/stdlib.c index 839673cdb..33ec0b751 100644 --- a/src/script/stdlib.c +++ b/src/script/stdlib.c @@ -3,10 +3,12 @@ * 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 +#include #include #include +#include +#include #include #ifdef M_CORE_GBA #include @@ -24,7 +26,14 @@ static uint32_t _mScriptCallbackAdd(struct mScriptCallbackManager* adapter, stru fn = mScriptValueUnwrap(fn); } uint32_t id = mScriptContextAddCallback(adapter->context, name->buffer, fn); - mScriptValueDeref(fn); + return id; +} + +static uint32_t _mScriptCallbackOneshot(struct mScriptCallbackManager* adapter, struct mScriptString* name, struct mScriptValue* fn) { + if (fn->type->base == mSCRIPT_TYPE_WRAPPER) { + fn = mScriptValueUnwrap(fn); + } + uint32_t id = mScriptContextAddOneshot(adapter->context, name->buffer, fn); return id; } @@ -34,6 +43,7 @@ static void _mScriptCallbackRemove(struct mScriptCallbackManager* adapter, uint3 mSCRIPT_DECLARE_STRUCT(mScriptCallbackManager); mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCallbackManager, U32, add, _mScriptCallbackAdd, 2, STR, callback, WRAPPER, function); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptCallbackManager, U32, oneshot, _mScriptCallbackOneshot, 2, STR, callback, WRAPPER, function); mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptCallbackManager, remove, _mScriptCallbackRemove, 1, U32, cbid); static uint64_t mScriptMakeBitmask(struct mScriptList* list) { @@ -71,19 +81,22 @@ mSCRIPT_BIND_FUNCTION(mScriptExpandBitmask_Binding, WLIST, mScriptExpandBitmask, mSCRIPT_DEFINE_STRUCT(mScriptCallbackManager) mSCRIPT_DEFINE_CLASS_DOCSTRING( "A global singleton object `callbacks` used for managing callbacks. The following callbacks are defined:\n\n" - "- **alarm**: An in-game alarm went off\n" - "- **crashed**: The emulation crashed\n" - "- **frame**: The emulation finished a frame\n" - "- **keysRead**: The emulation is about to read the key input\n" - "- **reset**: The emulation has been reset\n" - "- **savedataUpdated**: The emulation has just finished modifying save data\n" - "- **sleep**: The emulation has used the sleep feature to enter a low-power mode\n" - "- **shutdown**: The emulation has been powered off\n" - "- **start**: The emulation has started\n" - "- **stop**: The emulation has voluntarily shut down\n" + "- `alarm`: An in-game alarm went off\n" + "- `crashed`: The emulation crashed\n" + "- `frame`: The emulation finished a frame\n" + "- `keysRead`: The emulation is about to read the key input\n" + "- `reset`: The emulation has been reset\n" + "- `rumble`: The state of the rumble motor was changed. This callback is passed a single argument that specifies if it was turned on (true) or off (false)\n" + "- `savedataUpdated`: The emulation has just finished modifying save data\n" + "- `sleep`: The emulation has used the sleep feature to enter a low-power mode\n" + "- `shutdown`: The emulation has been powered off\n" + "- `start`: The emulation has started\n" + "- `stop`: The emulation has voluntarily shut down\n" ) mSCRIPT_DEFINE_DOCSTRING("Add a callback of the named type. The returned id can be used to remove it later") mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCallbackManager, add) + mSCRIPT_DEFINE_DOCSTRING("Add a one-shot callback of the named type that will be automatically removed after called. The returned id can be used to remove it early") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCallbackManager, oneshot) mSCRIPT_DEFINE_DOCSTRING("Remove a callback with the previously retuned id") mSCRIPT_DEFINE_STRUCT_METHOD(mScriptCallbackManager, remove) mSCRIPT_DEFINE_END; @@ -146,6 +159,15 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) { mSCRIPT_CONSTANT_PAIR(GB_KEY, DOWN), mSCRIPT_KV_SENTINEL }); +#endif +#ifdef USE_DEBUGGERS + mScriptContextExportConstants(context, "WATCHPOINT_TYPE", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(WATCHPOINT, WRITE), + mSCRIPT_CONSTANT_PAIR(WATCHPOINT, READ), + mSCRIPT_CONSTANT_PAIR(WATCHPOINT, RW), + mSCRIPT_CONSTANT_PAIR(WATCHPOINT, WRITE_CHANGE), + mSCRIPT_KV_SENTINEL + }); #endif mScriptContextSetGlobal(context, "C", context->constants); mScriptContextSetDocstring(context, "C", "A table containing the [exported constants](#constants)"); @@ -158,4 +180,27 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) { mScriptContextSetDocstring(context, "util", "Basic utility library"); mScriptContextSetDocstring(context, "util.makeBitmask", "Compile a list of bit indices into a bitmask"); mScriptContextSetDocstring(context, "util.expandBitmask", "Expand a bitmask into a list of bit indices"); + + struct mScriptValue* systemVersion = mScriptStringCreateFromUTF8(projectVersion); + struct mScriptValue* systemProgram = mScriptStringCreateFromUTF8(projectName); + struct mScriptValue* systemBranch = mScriptStringCreateFromUTF8(gitBranch); + struct mScriptValue* systemCommit = mScriptStringCreateFromUTF8(gitCommit); + struct mScriptValue* systemRevision = mScriptValueAlloc(mSCRIPT_TYPE_MS_S32); + systemRevision->value.s32 = gitRevision; + + mScriptContextExportNamespace(context, "system", (struct mScriptKVPair[]) { + mSCRIPT_KV_PAIR(version, systemVersion), + mSCRIPT_KV_PAIR(program, systemProgram), + mSCRIPT_KV_PAIR(branch, systemBranch), + mSCRIPT_KV_PAIR(commit, systemCommit), + mSCRIPT_KV_PAIR(revision, systemRevision), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextSetDocstring(context, "system", "Information about the system the script is running under"); + mScriptContextSetDocstring(context, "system.version", "The current version of this build of the program"); + mScriptContextSetDocstring(context, "system.program", "The name of the program. Generally this will be \\\"mGBA\\\", but forks may change it to differentiate"); + mScriptContextSetDocstring(context, "system.branch", "The current git branch of this build of the program, if known"); + mScriptContextSetDocstring(context, "system.commit", "The current git commit hash of this build of the program, if known"); + mScriptContextSetDocstring(context, "system.revision", "The current git revision number of this build of the program, or -1 if unknown"); } diff --git a/src/script/storage.c b/src/script/storage.c new file mode 100644 index 000000000..e1299d53e --- /dev/null +++ b/src/script/storage.c @@ -0,0 +1,557 @@ +/* Copyright (c) 2013-2023 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 + +#include +#include + +#include +#include + +#define STORAGE_LEN_MAX 64 + +struct mScriptStorageBucket { + char* name; + struct mScriptValue* root; + bool autoflush; + bool dirty; +}; + +struct mScriptStorageContext { + struct Table buckets; +}; + +void mScriptStorageBucketDeinit(void*); +struct mScriptValue* mScriptStorageBucketGet(struct mScriptStorageBucket* bucket, const char* key); +static void mScriptStorageBucketSet(struct mScriptStorageBucket* bucket, const char* key, struct mScriptValue* value); +static void mScriptStorageBucketSetVoid(struct mScriptStorageBucket* bucket, const char* key, struct mScriptValue* value); +static void mScriptStorageBucketSetSInt(struct mScriptStorageBucket* bucket, const char* key, int64_t value); +static void mScriptStorageBucketSetUInt(struct mScriptStorageBucket* bucket, const char* key, uint64_t value); +static void mScriptStorageBucketSetFloat(struct mScriptStorageBucket* bucket, const char* key, double value); +static void mScriptStorageBucketSetBool(struct mScriptStorageBucket* bucket, const char* key, bool value); +static bool mScriptStorageBucketReload(struct mScriptStorageBucket* bucket); +static bool mScriptStorageBucketFlush(struct mScriptStorageBucket* bucket); +static void mScriptStorageBucketEnableAutoFlush(struct mScriptStorageBucket* bucket, bool enable); + +static void mScriptStorageContextDeinit(struct mScriptStorageContext*); +static void mScriptStorageContextFlushAll(struct mScriptStorageContext*); +struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext*, const char* name); + +static bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out); +static struct mScriptValue* mScriptStorageFromJson(struct json_object* json); + +mSCRIPT_DECLARE_STRUCT(mScriptStorageBucket); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageBucket, WRAPPER, _get, mScriptStorageBucketGet, 1, CHARP, key); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setSInt, mScriptStorageBucketSetSInt, 2, CHARP, key, S64, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setUInt, mScriptStorageBucketSetUInt, 2, CHARP, key, U64, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setFloat, mScriptStorageBucketSetFloat, 2, CHARP, key, F64, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setBool, mScriptStorageBucketSetBool, 2, CHARP, key, BOOL, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setStr, mScriptStorageBucketSet, 2, CHARP, key, WSTR, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setList, mScriptStorageBucketSet, 2, CHARP, key, WLIST, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setTable, mScriptStorageBucketSet, 2, CHARP, key, WTABLE, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, setVoid, mScriptStorageBucketSetVoid, 2, CHARP, key, NUL, value); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageBucket, BOOL, reload, mScriptStorageBucketReload, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageBucket, BOOL, flush, mScriptStorageBucketFlush, 0); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageBucket, enableAutoFlush, mScriptStorageBucketEnableAutoFlush, 1, BOOL, enable); + +mSCRIPT_DEFINE_STRUCT(mScriptStorageBucket) + mSCRIPT_DEFINE_CLASS_DOCSTRING( + "A single 'bucket' of stored data, appropriate for a single script to store its data. " + "Fields can be set directly on the bucket objct, e.g. if you want to store a value called " + "`foo` on a bucket named `bucket`, you can directly assign to it as `bucket.foo = value`, " + "and retrieve it in the same way later. Primitive types (numbers, strings, lists and tables) " + "can be stored in buckets, but complex data types (e.g. a bucket itself) cannot. Data " + "stored in a bucket is periodically flushed to disk and persists between sessions." + ) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setSInt) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setUInt) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setFloat) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setBool) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setStr) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setList) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setTable) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(mScriptStorageBucket, setVoid) + mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(mScriptStorageBucket) + mSCRIPT_DEFINE_DOCSTRING("Reload the state of the bucket from disk") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageBucket, reload) + mSCRIPT_DEFINE_DOCSTRING("Flush the bucket to disk manually") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageBucket, flush) + mSCRIPT_DEFINE_DOCSTRING( + "Enable or disable the automatic flushing of this bucket. This is good for ensuring buckets " + "don't get flushed in an inconsistent state. It will also disable flushing to disk when the " + "emulator is shut down, so make sure to either manually flush the bucket or re-enable " + "automatic flushing whenever you're done updating it if you do disable it prior." + ) + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageBucket, enableAutoFlush) +mSCRIPT_DEFINE_END; + +mSCRIPT_DECLARE_STRUCT(mScriptStorageContext); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageContext, _deinit, mScriptStorageContextDeinit, 0); +mSCRIPT_DECLARE_STRUCT_METHOD(mScriptStorageContext, S(mScriptStorageBucket), getBucket, mScriptStorageGetBucket, 1, CHARP, key); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptStorageContext, flushAll, mScriptStorageContextFlushAll, 0); + +mSCRIPT_DEFINE_STRUCT(mScriptStorageContext) + mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptStorageContext) + mSCRIPT_DEFINE_DOCSTRING( + "Get a bucket with the given name. Names can contain letters, numbers, " + "underscores and periods. If a given bucket doesn't exist, it is created." + ) + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageContext, getBucket) + mSCRIPT_DEFINE_DOCSTRING("Flush all buckets to disk manually") + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptStorageContext, flushAll) +mSCRIPT_DEFINE_END; + +struct mScriptValue* mScriptStorageBucketGet(struct mScriptStorageBucket* bucket, const char* key) { + struct mScriptValue* val = mScriptTableLookup(bucket->root, &mSCRIPT_MAKE_CHARP(key)); + if (val) { + mScriptValueRef(val); + } + return val; +} + +void mScriptStorageBucketSet(struct mScriptStorageBucket* bucket, const char* key, struct mScriptValue* value) { + struct mScriptValue* vkey = mScriptStringCreateFromUTF8(key); + if (value->type->base == mSCRIPT_TYPE_WRAPPER) { + value = mScriptValueUnwrap(value); + } + mScriptTableInsert(bucket->root, vkey, value); + mScriptValueDeref(vkey); + bucket->dirty = true; +} + +void mScriptStorageBucketSetVoid(struct mScriptStorageBucket* bucket, const char* key, struct mScriptValue* value) { + UNUSED(value); + struct mScriptValue* vkey = mScriptStringCreateFromUTF8(key); + mScriptTableInsert(bucket->root, vkey, &mScriptValueNull); + mScriptValueDeref(vkey); + bucket->dirty = true; +} + +#define MAKE_SCALAR_SETTER(NAME, TYPE) \ + void mScriptStorageBucketSet ## NAME (struct mScriptStorageBucket* bucket, const char* key, mSCRIPT_TYPE_C_ ## TYPE value) { \ + struct mScriptValue* vkey = mScriptStringCreateFromUTF8(key); \ + struct mScriptValue* vval = mScriptValueAlloc(mSCRIPT_TYPE_MS_ ## TYPE); \ + vval->value.mSCRIPT_TYPE_FIELD_ ## TYPE = value; \ + mScriptTableInsert(bucket->root, vkey, vval); \ + mScriptValueDeref(vkey); \ + mScriptValueDeref(vval); \ + bucket->dirty = true; \ + } + +MAKE_SCALAR_SETTER(SInt, S64) +MAKE_SCALAR_SETTER(UInt, U64) +MAKE_SCALAR_SETTER(Float, F64) +MAKE_SCALAR_SETTER(Bool, BOOL) + +void mScriptStorageGetBucketPath(const char* bucket, char* out) { + mCoreConfigDirectory(out, PATH_MAX); + + strncat(out, PATH_SEP "storage" PATH_SEP, PATH_MAX - 1); +#ifdef _WIN32 + // TODO: Move this to vfs somewhere + WCHAR wout[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, out, -1, wout, MAX_PATH); + CreateDirectoryW(wout, NULL); +#else + mkdir(out, 0755); +#endif + + char suffix[STORAGE_LEN_MAX + 6]; + snprintf(suffix, sizeof(suffix), "%s.json", bucket); + strncat(out, suffix, PATH_MAX - 1); +} + +static struct json_object* _tableToJson(struct mScriptValue* rootVal) { + bool ok = true; + + struct TableIterator iter; + struct json_object* rootObj = json_object_new_object(); + if (mScriptTableIteratorStart(rootVal, &iter)) { + do { + struct mScriptValue* key = mScriptTableIteratorGetKey(rootVal, &iter); + struct mScriptValue* value = mScriptTableIteratorGetValue(rootVal, &iter); + const char* ckey; + if (key->type == mSCRIPT_TYPE_MS_CHARP) { + ckey = key->value.copaque; + } else if (key->type == mSCRIPT_TYPE_MS_STR) { + ckey = key->value.string->buffer; + } else { + ok = false; + break; + } + + struct json_object* obj; + ok = mScriptStorageToJson(value, &obj); + + if (ok) { +#if JSON_C_VERSION_NUM >= (13 << 8) + ok = json_object_object_add(rootObj, ckey, obj) >= 0; +#else + json_object_object_add(rootObj, ckey, obj); +#endif + } + } while (mScriptTableIteratorNext(rootVal, &iter) && ok); + } + if (!ok) { + json_object_put(rootObj); + return NULL; + } + return rootObj; +} + +bool mScriptStorageToJson(struct mScriptValue* value, struct json_object** out) { + if (value->type->base == mSCRIPT_TYPE_WRAPPER) { + value = mScriptValueUnwrap(value); + } + + size_t i; + bool ok = true; + struct json_object* obj = NULL; + switch (value->type->base) { + case mSCRIPT_TYPE_SINT: + obj = json_object_new_int64(value->value.s64); + break; + case mSCRIPT_TYPE_UINT: + if (value->type == mSCRIPT_TYPE_MS_BOOL) { + obj = json_object_new_boolean(value->value.u32); + break; + } +#if JSON_C_VERSION_NUM >= (14 << 8) + obj = json_object_new_uint64(value->value.u64); +#else + if (value->value.u64 < (uint64_t) INT64_MAX) { + obj = json_object_new_int64(value->value.u64); + } else { + obj = json_object_new_double(value->value.u64); + } +#endif + break; + case mSCRIPT_TYPE_FLOAT: + obj = json_object_new_double(value->value.f64); + break; + case mSCRIPT_TYPE_STRING: + obj = json_object_new_string_len(value->value.string->buffer, value->value.string->size); + break; + case mSCRIPT_TYPE_LIST: +#if JSON_C_VERSION_NUM >= (15 << 8) + obj = json_object_new_array_ext(mScriptListSize(value->value.list)); +#else + obj = json_object_new_array(); +#endif + for (i = 0; i < mScriptListSize(value->value.list); ++i) { + struct json_object* listObj; + ok = mScriptStorageToJson(mScriptListGetPointer(value->value.list, i), &listObj); + if (!ok) { + break; + } + json_object_array_add(obj, listObj); + } + break; + case mSCRIPT_TYPE_TABLE: + obj = _tableToJson(value); + if (!obj) { + ok = false; + } + break; + case mSCRIPT_TYPE_VOID: + obj = NULL; + break; + default: + ok = false; + break; + } + + if (!ok) { + if (obj) { + json_object_put(obj); + } + *out = NULL; + } else { + *out = obj; + } + return ok; +} + +#ifndef JSON_C_TO_STRING_PRETTY_TAB +#define JSON_C_TO_STRING_PRETTY_TAB 0 +#endif + +static bool _mScriptStorageBucketFlushVF(struct mScriptStorageBucket* bucket, struct VFile* vf) { + struct json_object* rootObj; + bool ok = mScriptStorageToJson(bucket->root, &rootObj); + if (!ok) { + vf->close(vf); + return false; + } + + const char* json = json_object_to_json_string_ext(rootObj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_PRETTY_TAB); + if (!json) { + json_object_put(rootObj); + vf->close(vf); + return false; + } + + vf->write(vf, json, strlen(json)); + vf->close(vf); + + bucket->dirty = false; + + json_object_put(rootObj); + return true; +} + +bool mScriptStorageBucketFlush(struct mScriptStorageBucket* bucket) { + char path[PATH_MAX]; + mScriptStorageGetBucketPath(bucket->name, path); + struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + if (!vf) { + return false; + } + return _mScriptStorageBucketFlushVF(bucket, vf); +} + +void mScriptStorageBucketEnableAutoFlush(struct mScriptStorageBucket* bucket, bool enable) { + bucket->autoflush = enable; +} + +bool mScriptStorageSaveBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) { + struct mScriptValue* value = mScriptContextGetGlobal(context, "storage"); + if (!value) { + vf->close(vf); + return false; + } + struct mScriptStorageContext* storage = value->value.opaque; + struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName); + return _mScriptStorageBucketFlushVF(bucket, vf); +} + +bool mScriptStorageSaveBucket(struct mScriptContext* context, const char* bucketName) { + char path[PATH_MAX]; + mScriptStorageGetBucketPath(bucketName, path); + struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + if (!vf) { + return false; + } + return mScriptStorageSaveBucketVF(context, bucketName, vf); +} + +struct mScriptValue* mScriptStorageFromJson(struct json_object* json) { + enum json_type type = json_object_get_type(json); + struct mScriptValue* value = NULL; + switch (type) { + case json_type_null: + return &mScriptValueNull; + case json_type_int: + value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S64); + value->value.s64 = json_object_get_int64(json); + break; + case json_type_double: + value = mScriptValueAlloc(mSCRIPT_TYPE_MS_F64); + value->value.f64 = json_object_get_double(json); + break; + case json_type_boolean: + value = mScriptValueAlloc(mSCRIPT_TYPE_MS_BOOL); + value->value.u32 = json_object_get_boolean(json); + break; + case json_type_string: + value = mScriptStringCreateFromBytes(json_object_get_string(json), json_object_get_string_len(json)); + break; + case json_type_array: + value = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST); + { + size_t i; + for (i = 0; i < json_object_array_length(json); ++i) { + struct mScriptValue* vval = mScriptStorageFromJson(json_object_array_get_idx(json, i)); + if (!vval) { + mScriptValueDeref(value); + value = NULL; + break; + } + mScriptValueWrap(vval, mScriptListAppend(value->value.list)); + mScriptValueDeref(vval); + } + } + break; + case json_type_object: + value = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE); + { + json_object_object_foreach(json, jkey, jval) { + struct mScriptValue* vval = mScriptStorageFromJson(jval); + if (!vval) { + mScriptValueDeref(value); + value = NULL; + break; + } + struct mScriptValue* vkey = mScriptStringCreateFromUTF8(jkey); + mScriptTableInsert(value, vkey, vval); + mScriptValueDeref(vkey); + mScriptValueDeref(vval); + } + } + break; + } + return value; +} + +static struct mScriptValue* _mScriptStorageLoadJson(struct VFile* vf) { + ssize_t size = vf->size(vf); + if (size < 2) { + vf->close(vf); + return NULL; + } + char* json = calloc(1, size + 1); + if (vf->read(vf, json, size) != size) { + vf->close(vf); + return NULL; + } + vf->close(vf); + + struct json_object* obj = json_tokener_parse(json); + free(json); + if (!obj) { + return NULL; + } + + struct mScriptValue* root = mScriptStorageFromJson(obj); + json_object_put(obj); + return root; +} + +bool mScriptStorageBucketReload(struct mScriptStorageBucket* bucket) { + char path[PATH_MAX]; + mScriptStorageGetBucketPath(bucket->name, path); + struct VFile* vf = VFileOpen(path, O_RDONLY); + if (!vf) { + return false; + } + struct mScriptValue* root = _mScriptStorageLoadJson(vf); + if (!root) { + return false; + } + if (bucket->root) { + mScriptValueDeref(bucket->root); + } + bucket->root = root; + + bucket->dirty = false; + + return true; +} + +bool mScriptStorageLoadBucketVF(struct mScriptContext* context, const char* bucketName, struct VFile* vf) { + struct mScriptValue* value = mScriptContextGetGlobal(context, "storage"); + if (!value) { + vf->close(vf); + return false; + } + struct mScriptStorageContext* storage = value->value.opaque; + struct mScriptValue* root = _mScriptStorageLoadJson(vf); + if (!root) { + return false; + } + struct mScriptStorageBucket* bucket = mScriptStorageGetBucket(storage, bucketName); + mScriptValueDeref(bucket->root); + bucket->root = root; + + bucket->dirty = false; + + return true; +} + +bool mScriptStorageLoadBucket(struct mScriptContext* context, const char* bucketName) { + char path[PATH_MAX]; + mScriptStorageGetBucketPath(bucketName, path); + struct VFile* vf = VFileOpen(path, O_RDONLY); + if (!vf) { + return false; + } + return mScriptStorageLoadBucketVF(context, bucketName, vf); +} + +void mScriptContextAttachStorage(struct mScriptContext* context) { + struct mScriptStorageContext* storage = calloc(1, sizeof(*storage)); + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptStorageContext)); + value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; + value->value.opaque = storage; + + HashTableInit(&storage->buckets, 0, mScriptStorageBucketDeinit); + + mScriptContextSetGlobal(context, "storage", value); + mScriptContextSetDocstring(context, "storage", "Singleton instance of struct::mScriptStorageContext"); +} + +void mScriptStorageFlushAll(struct mScriptContext* context) { + struct mScriptValue* value = mScriptContextGetGlobal(context, "storage"); + if (!value) { + return; + } + struct mScriptStorageContext* storage = value->value.opaque; + mScriptStorageContextFlushAll(storage); +} + +void mScriptStorageContextDeinit(struct mScriptStorageContext* storage) { + HashTableDeinit(&storage->buckets); +} + +void mScriptStorageContextFlushAll(struct mScriptStorageContext* storage) { + struct TableIterator iter; + if (HashTableIteratorStart(&storage->buckets, &iter)) { + do { + struct mScriptStorageBucket* bucket = HashTableIteratorGetValue(&storage->buckets, &iter); + if (bucket->autoflush) { + mScriptStorageBucketFlush(bucket); + } + } while (HashTableIteratorNext(&storage->buckets, &iter)); + } +} + +struct mScriptStorageBucket* mScriptStorageGetBucket(struct mScriptStorageContext* storage, const char* name) { + if (!name) { + return NULL; + } + + // Check if name is allowed + // Currently only names matching /[0-9A-Za-z][0-9A-Za-z_.]*/ are allowed + size_t i; + for (i = 0; name[i]; ++i) { + if (i >= STORAGE_LEN_MAX) { + return NULL; + } + if (isalnum(name[i])) { + continue; + } + if (name[i] == '_') { + continue; + } + if (i > 0 && name[i] == '.') { + continue; + } + return NULL; + } + struct mScriptStorageBucket* bucket = HashTableLookup(&storage->buckets, name); + if (bucket) { + return bucket; + } + + bucket = calloc(1, sizeof(*bucket)); + bucket->name = strdup(name); + bucket->autoflush = true; + if (!mScriptStorageBucketReload(bucket)) { + bucket->root = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE); + } + HashTableInsert(&storage->buckets, name, bucket); + return bucket; +} + +void mScriptStorageBucketDeinit(void* data) { + struct mScriptStorageBucket* bucket = data; + if (bucket->dirty) { + mScriptStorageBucketFlush(bucket); + } + mScriptValueDeref(bucket->root); + free(bucket->name); + free(bucket); +} diff --git a/src/script/test/classes.c b/src/script/test/classes.c index 476e24455..f7c5eb128 100644 --- a/src/script/test/classes.c +++ b/src/script/test/classes.c @@ -5,15 +5,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "util/test/suite.h" -#include -#include -#include +#include struct TestA { int32_t i; int32_t i2; int8_t b8; int16_t hUnaligned; + char str[6]; + struct mScriptValue table; + struct mScriptList list; int32_t (*ifn0)(struct TestA*); int32_t (*ifn1)(struct TestA*, int); void (*vfn0)(struct TestA*); @@ -43,6 +44,19 @@ struct TestF { int* ref; }; +struct TestG { + const char* name; + int64_t s; + uint64_t u; + double f; + const char* c; +}; + +struct TestH { + int32_t i; + int32_t j; +}; + static int32_t testAi0(struct TestA* a) { return a->i; } @@ -80,6 +94,26 @@ static void testDeinit(struct TestF* f) { ++*f->ref; } +static void testSetS(struct TestG* g, const char* name, int64_t val) { + g->name = name; + g->s = val; +} + +static void testSetU(struct TestG* g, const char* name, uint64_t val) { + g->name = name; + g->u = val; +} + +static void testSetF(struct TestG* g, const char* name, double val) { + g->name = name; + g->f = val; +} + +static void testSetC(struct TestG* g, const char* name, const char* val) { + g->name = name; + g->c = val; +} + #define MEMBER_A_DOCSTRING "Member a" mSCRIPT_DECLARE_STRUCT(TestA); @@ -103,6 +137,9 @@ mSCRIPT_DEFINE_STRUCT(TestA) mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S32, i2) mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S8, b8) mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, S16, hUnaligned) + mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, CHARP, str) + mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, TABLE, table) + mSCRIPT_DEFINE_STRUCT_MEMBER(TestA, LIST, list) mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn0) mSCRIPT_DEFINE_STRUCT_METHOD(TestA, ifn1) mSCRIPT_DEFINE_STRUCT_METHOD(TestA, icfn0) @@ -151,6 +188,25 @@ mSCRIPT_DEFINE_STRUCT(TestF) mSCRIPT_DEFINE_STRUCT_DEINIT(TestF) mSCRIPT_DEFINE_END; +mSCRIPT_DECLARE_STRUCT(TestG); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestG, setS, testSetS, 2, CHARP, name, S64, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestG, setU, testSetU, 2, CHARP, name, U64, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestG, setF, testSetF, 2, CHARP, name, F64, value); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(TestG, setC, testSetC, 2, CHARP, name, CHARP, value); + +mSCRIPT_DEFINE_STRUCT(TestG) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TestG, setS) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TestG, setU) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TestG, setF) + mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TestG, setC) +mSCRIPT_DEFINE_END; + + +mSCRIPT_DEFINE_STRUCT(TestH) + mSCRIPT_DEFINE_STRUCT_MEMBER(TestH, S32, i) + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(TestH, S32, j) +mSCRIPT_DEFINE_END; + M_TEST_DEFINE(testALayout) { struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls; assert_false(cls->init); @@ -187,6 +243,27 @@ M_TEST_DEFINE(testALayout) { assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_S16); assert_int_not_equal(member->offset, sizeof(int32_t) * 2 + 1); + member = HashTableLookup(&cls->instanceMembers, "str"); + assert_non_null(member); + assert_string_equal(member->name, "str"); + assert_null(member->docstring); + assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_CHARP); + assert_int_equal(member->offset, &((struct TestA*) 0)->str); + + member = HashTableLookup(&cls->instanceMembers, "table"); + assert_non_null(member); + assert_string_equal(member->name, "table"); + assert_null(member->docstring); + assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_TABLE); + assert_int_equal(member->offset, &((struct TestA*) 0)->table); + + member = HashTableLookup(&cls->instanceMembers, "list"); + assert_non_null(member); + assert_string_equal(member->name, "list"); + assert_null(member->docstring); + assert_ptr_equal(member->type, mSCRIPT_TYPE_MS_LIST); + assert_int_equal(member->offset, &((struct TestA*) 0)->list); + member = HashTableLookup(&cls->instanceMembers, "unknown"); assert_null(member); @@ -280,6 +357,14 @@ M_TEST_DEFINE(testAGet) { .hUnaligned = 4 }; + mScriptListInit(&s.list, 1); + *mScriptListAppend(&s.list) = mSCRIPT_MAKE_S32(5); + + s.table.type = mSCRIPT_TYPE_MS_TABLE; + s.table.type->alloc(&s.table); + + strcpy(s.str, "test"); + struct mScriptValue sval = mSCRIPT_MAKE_S(TestA, &s); struct mScriptValue val; struct mScriptValue compare; @@ -300,8 +385,38 @@ M_TEST_DEFINE(testAGet) { assert_true(mScriptObjectGet(&sval, "hUnaligned", &val)); assert_true(compare.type->equal(&compare, &val)); + compare = mSCRIPT_MAKE_CHARP("test"); + assert_true(mScriptObjectGet(&sval, "str", &val)); + assert_true(compare.type->equal(&compare, &val)); + + compare = mSCRIPT_MAKE_S32(5); + assert_true(mScriptObjectGet(&sval, "list", &val)); + assert_ptr_equal(val.type, mSCRIPT_TYPE_MS_LIST); + assert_int_equal(mScriptListSize(val.value.list), 1); + assert_true(compare.type->equal(&compare, mScriptListGetPointer(val.value.list, 0))); + + *mScriptListAppend(&s.list) = mSCRIPT_MAKE_S32(6); + compare = mSCRIPT_MAKE_S32(6); + assert_int_equal(mScriptListSize(val.value.list), 2); + assert_true(compare.type->equal(&compare, mScriptListGetPointer(val.value.list, 1))); + + struct mScriptValue* ival = &val; + assert_true(mScriptObjectGet(&sval, "table", &val)); + if (val.type->base == mSCRIPT_TYPE_WRAPPER) { + ival = mScriptValueUnwrap(&val); + } + assert_ptr_equal(ival->type, mSCRIPT_TYPE_MS_TABLE); + assert_int_equal(mScriptTableSize(ival), 0); + compare = mSCRIPT_MAKE_S32(7); + mScriptTableInsert(&s.table, &compare, &compare); + assert_int_equal(mScriptTableSize(&s.table), 1); + assert_int_equal(mScriptTableSize(ival), 1); + assert_false(mScriptObjectGet(&sval, "unknown", &val)); + mScriptListDeinit(&s.list); + mSCRIPT_TYPE_MS_TABLE->free(&s.table); + assert_true(cls->init); mScriptClassDeinit(cls); assert_false(cls->init); @@ -967,6 +1082,108 @@ M_TEST_DEFINE(testFDeinit) { assert_false(cls->init); } +M_TEST_DEFINE(testGSet) { + struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestG)->details.cls; + + struct TestG s = { + }; + + assert_int_equal(s.s, 0); + assert_int_equal(s.u, 0); + assert_float_equal(s.f, 0, 0); + assert_null(s.c); + + struct mScriptValue sval = mSCRIPT_MAKE_S(TestG, &s); + struct mScriptValue val; + struct mScriptValue* pval; + + val = mSCRIPT_MAKE_S64(1); + assert_true(mScriptObjectSet(&sval, "a", &val)); + assert_int_equal(s.s, 1); + assert_string_equal(s.name, "a"); + + val = mSCRIPT_MAKE_U64(2); + assert_true(mScriptObjectSet(&sval, "b", &val)); + assert_int_equal(s.u, 2); + assert_string_equal(s.name, "b"); + + val = mSCRIPT_MAKE_F64(1.5); + assert_true(mScriptObjectSet(&sval, "c", &val)); + assert_float_equal(s.f, 1.5, 0); + assert_string_equal(s.name, "c"); + + val = mSCRIPT_MAKE_CHARP("hello"); + assert_true(mScriptObjectSet(&sval, "d", &val)); + assert_string_equal(s.c, "hello"); + assert_string_equal(s.name, "d"); + + val = mSCRIPT_MAKE_S32(3); + assert_true(mScriptObjectSet(&sval, "a", &val)); + assert_int_equal(s.s, 3); + + val = mSCRIPT_MAKE_S16(4); + assert_true(mScriptObjectSet(&sval, "a", &val)); + assert_int_equal(s.s, 4); + + val = mSCRIPT_MAKE_S8(5); + assert_true(mScriptObjectSet(&sval, "a", &val)); + assert_int_equal(s.s, 5); + + val = mSCRIPT_MAKE_BOOL(false); + assert_true(mScriptObjectSet(&sval, "a", &val)); + assert_int_equal(s.u, 0); + + pval = mScriptStringCreateFromASCII("goodbye"); + assert_true(mScriptObjectSet(&sval, "a", pval)); + assert_string_equal(s.c, "goodbye"); + mScriptValueDeref(pval); + + assert_true(cls->init); + mScriptClassDeinit(cls); + assert_false(cls->init); +} + +M_TEST_DEFINE(testHSet) { + struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestH)->details.cls; + + struct TestH s = { + .i = 1, + .j = 2, + }; + + struct mScriptValue sval = mSCRIPT_MAKE_S(TestH, &s); + struct mScriptValue val; + struct mScriptValue compare; + + compare = mSCRIPT_MAKE_S32(1); + assert_true(mScriptObjectGet(&sval, "i", &val)); + assert_true(compare.type->equal(&compare, &val)); + + compare = mSCRIPT_MAKE_S32(2); + assert_true(mScriptObjectGet(&sval, "j", &val)); + assert_true(compare.type->equal(&compare, &val)); + + val = mSCRIPT_MAKE_S32(3); + assert_true(mScriptObjectSet(&sval, "i", &val)); + assert_int_equal(s.i, 3); + + val = mSCRIPT_MAKE_S32(4); + assert_false(mScriptObjectSet(&sval, "j", &val)); + assert_int_equal(s.j, 2); + + compare = mSCRIPT_MAKE_S32(3); + assert_true(mScriptObjectGet(&sval, "i", &val)); + assert_true(compare.type->equal(&compare, &val)); + + compare = mSCRIPT_MAKE_S32(2); + assert_true(mScriptObjectGet(&sval, "j", &val)); + assert_true(compare.type->equal(&compare, &val)); + + assert_true(cls->init); + mScriptClassDeinit(cls); + assert_false(cls->init); +} + M_TEST_SUITE_DEFINE(mScriptClasses, cmocka_unit_test(testALayout), cmocka_unit_test(testASignatures), @@ -982,4 +1199,6 @@ M_TEST_SUITE_DEFINE(mScriptClasses, cmocka_unit_test(testDSet), cmocka_unit_test(testEGet), cmocka_unit_test(testFDeinit), + cmocka_unit_test(testGSet), + cmocka_unit_test(testHSet), ) diff --git a/src/script/test/context.c b/src/script/test/context.c new file mode 100644 index 000000000..da3ff7ea8 --- /dev/null +++ b/src/script/test/context.c @@ -0,0 +1,101 @@ +/* Copyright (c) 2013-2023 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 + +M_TEST_DEFINE(weakrefBasic) { + struct mScriptContext context; + mScriptContextInit(&context); + + struct mScriptValue weakref = mSCRIPT_VAL(WEAKREF, 1); + struct mScriptValue fakeVal = mSCRIPT_S32(0x7E57CA5E); + struct mScriptValue* val; + + assert_int_equal(TableSize(&context.weakrefs), 0); + assert_null(TableLookup(&context.weakrefs, 1)); + assert_int_equal(context.nextWeakref, 1); + assert_null(mScriptContextAccessWeakref(&context, &weakref)); + + assert_int_equal(mScriptContextSetWeakref(&context, &fakeVal), 1); + assert_int_equal(context.nextWeakref, 2); + assert_int_equal(TableSize(&context.weakrefs), 1); + val = mScriptContextAccessWeakref(&context, &weakref); + assert_non_null(val); + assert_int_equal(val->value.u32, 0x7E57CA5E); + + mScriptContextClearWeakref(&context, 1); + + assert_int_equal(TableSize(&context.weakrefs), 0); + assert_null(TableLookup(&context.weakrefs, 1)); + assert_int_equal(context.nextWeakref, 2); + assert_null(mScriptContextAccessWeakref(&context, &weakref)); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(drainPool) { + struct mScriptContext context; + mScriptContextInit(&context); + + assert_int_equal(mScriptListSize(&context.refPool), 0); + + struct mScriptValue fakeVal = mSCRIPT_CHARP("foo"); + fakeVal.refs = 2; + + mScriptContextFillPool(&context, &fakeVal); + assert_int_equal(mScriptListSize(&context.refPool), 1); + assert_int_equal(fakeVal.refs, 2); + + mScriptContextDrainPool(&context); + assert_int_equal(mScriptListSize(&context.refPool), 0); + assert_int_equal(fakeVal.refs, 1); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(disownWeakref) { + struct mScriptContext context; + mScriptContextInit(&context); + + struct mScriptValue weakref = mSCRIPT_VAL(WEAKREF, 1); + struct mScriptValue fakeVal = mSCRIPT_S32(0x7E57CA5E); + struct mScriptValue* val; + + assert_int_equal(mScriptListSize(&context.refPool), 0); + assert_int_equal(TableSize(&context.weakrefs), 0); + assert_null(TableLookup(&context.weakrefs, 1)); + assert_int_equal(context.nextWeakref, 1); + assert_null(mScriptContextAccessWeakref(&context, &weakref)); + + assert_int_equal(mScriptContextSetWeakref(&context, &fakeVal), 1); + assert_int_equal(TableSize(&context.weakrefs), 1); + assert_int_equal(context.nextWeakref, 2); + val = mScriptContextAccessWeakref(&context, &weakref); + assert_non_null(val); + assert_int_equal(val->value.u32, 0x7E57CA5E); + + mScriptContextDisownWeakref(&context, 1); + assert_int_equal(mScriptListSize(&context.refPool), 1); + assert_int_equal(TableSize(&context.weakrefs), 1); + val = mScriptContextAccessWeakref(&context, &weakref); + assert_non_null(val); + assert_int_equal(val->value.u32, 0x7E57CA5E); + + mScriptContextDrainPool(&context); + assert_int_equal(mScriptListSize(&context.refPool), 0); + assert_int_equal(TableSize(&context.weakrefs), 0); + assert_null(TableLookup(&context.weakrefs, 1)); + assert_null(mScriptContextAccessWeakref(&context, &weakref)); + + mScriptContextDeinit(&context); +} + +M_TEST_SUITE_DEFINE(mScript, + cmocka_unit_test(weakrefBasic), + cmocka_unit_test(drainPool), + cmocka_unit_test(disownWeakref), +) diff --git a/src/script/test/image.c b/src/script/test/image.c new file mode 100644 index 000000000..88901d780 --- /dev/null +++ b/src/script/test/image.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2013-2023 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 +#include + +#include "script/test.h" + +#define SETUP_LUA \ + struct mScriptContext context; \ + mScriptContextInit(&context); \ + struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \ + mScriptContextAttachStdlib(&context); \ + mScriptContextAttachImage(&context) + +M_TEST_SUITE_SETUP(mScriptImage) { + if (mSCRIPT_ENGINE_LUA->init) { + mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_SUITE_TEARDOWN(mScriptImage) { + if (mSCRIPT_ENGINE_LUA->deinit) { + mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_DEFINE(members) { + SETUP_LUA; + + TEST_PROGRAM("assert(image)"); + TEST_PROGRAM("assert(image.new)"); + TEST_PROGRAM("assert(image.load)"); + TEST_PROGRAM("im = image.new(1, 1)"); + TEST_PROGRAM("assert(im)"); + TEST_PROGRAM("assert(im.width == 1)"); + TEST_PROGRAM("assert(im.height == 1)"); + TEST_PROGRAM("assert(im.save)"); + TEST_PROGRAM("assert(im.save)"); + TEST_PROGRAM("assert(im.getPixel)"); + TEST_PROGRAM("assert(im.setPixel)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(zeroDim) { + SETUP_LUA; + + TEST_PROGRAM("im = image.new(0, 0)"); + TEST_PROGRAM("assert(not im)"); + TEST_PROGRAM("im = image.new(1, 0)"); + TEST_PROGRAM("assert(not im)"); + TEST_PROGRAM("im = image.new(0, 1)"); + TEST_PROGRAM("assert(not im)"); + TEST_PROGRAM("im = image.new(1, 1)"); + TEST_PROGRAM("assert(im)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(pixelColorDefault) { + SETUP_LUA; + + TEST_PROGRAM("im = image.new(1, 1)"); + TEST_PROGRAM("assert(im:getPixel(0, 0) == 0)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(pixelColorRoundTrip) { + SETUP_LUA; + + TEST_PROGRAM("im = image.new(1, 1)"); + TEST_PROGRAM("im:setPixel(0, 0, 0xFF123456)"); + TEST_PROGRAM("assert(im:getPixel(0, 0) == 0xFF123456)"); + + mScriptContextDeinit(&context); +} + +#ifdef USE_PNG +M_TEST_DEFINE(saveLoadRoundTrip) { + SETUP_LUA; + + unlink("tmp.png"); + TEST_PROGRAM("im = image.new(1, 1)"); + TEST_PROGRAM("im:setPixel(0, 0, 0xFF123456)"); + TEST_PROGRAM("assert(im:save('tmp.png'))"); + TEST_PROGRAM("im = image.load('tmp.png')"); + TEST_PROGRAM("assert(im)"); + TEST_PROGRAM("assert(im:getPixel(0, 0) == 0xFF123456)"); + unlink("tmp.png"); + + mScriptContextDeinit(&context); +} +#endif + +M_TEST_DEFINE(painterBasic) { + SETUP_LUA; + + TEST_PROGRAM("im = image.new(1, 1)"); + TEST_PROGRAM("painter = image.newPainter(im)"); + TEST_PROGRAM("assert(painter)"); + TEST_PROGRAM("painter:setFill(true)"); + TEST_PROGRAM("painter:setFillColor(0xFF123456)"); + TEST_PROGRAM("painter:drawRectangle(0, 0, 1, 1)"); + TEST_PROGRAM("assert(im:getPixel(0, 0) == 0xFF123456)"); + + mScriptContextDeinit(&context); +} + +M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptImage, + cmocka_unit_test(members), + cmocka_unit_test(zeroDim), + cmocka_unit_test(pixelColorDefault), + cmocka_unit_test(pixelColorRoundTrip), +#ifdef USE_PNG + cmocka_unit_test(saveLoadRoundTrip), +#endif + cmocka_unit_test(painterBasic), +) diff --git a/src/script/test/input.c b/src/script/test/input.c new file mode 100644 index 000000000..4c689a6ef --- /dev/null +++ b/src/script/test/input.c @@ -0,0 +1,223 @@ +/* Copyright (c) 2013-2022 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 +#include + +#include "script/test.h" + +#define SETUP_LUA \ + struct mScriptContext context; \ + mScriptContextInit(&context); \ + struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \ + mScriptContextAttachStdlib(&context); \ + mScriptContextAttachInput(&context) + +M_TEST_SUITE_SETUP(mScriptInput) { + if (mSCRIPT_ENGINE_LUA->init) { + mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_SUITE_TEARDOWN(mScriptInput) { + if (mSCRIPT_ENGINE_LUA->deinit) { + mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_DEFINE(members) { + SETUP_LUA; + + TEST_PROGRAM("assert(input)"); + TEST_PROGRAM("assert(input.seq == 0)"); + TEST_PROGRAM("assert(input.isKeyActive)"); + + mScriptContextDeinit(&context); +} +M_TEST_DEFINE(seq) { + SETUP_LUA; + + TEST_PROGRAM("assert(input.seq == 0)"); + + TEST_PROGRAM( + "seq = nil\n" + "function cb(ev)\n" + " seq = ev.seq\n" + "end\n" + "id = callbacks:add('key', cb)\n" + ); + + struct mScriptKeyEvent keyEvent = { + .d = { .type = mSCRIPT_EV_TYPE_KEY }, + .state = mSCRIPT_INPUT_STATE_DOWN, + }; + + mScriptContextFireEvent(&context, &keyEvent.d); + TEST_PROGRAM("assert(input.seq == 1)"); + TEST_PROGRAM("assert(seq == 0)"); + + mScriptContextFireEvent(&context, &keyEvent.d); + TEST_PROGRAM("assert(input.seq == 2)"); + TEST_PROGRAM("assert(seq == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(fireKey) { + SETUP_LUA; + + TEST_PROGRAM("assert(not input:isKeyActive('a'))"); + + TEST_PROGRAM( + "activeKey = false\n" + "state = nil\n" + "function cb(ev)\n" + " assert(ev.type == C.EV_TYPE.KEY)\n" + " activeKey = string.char(ev.key)\n" + " state = ev.state\n" + "end\n" + "id = callbacks:add('key', cb)\n" + "assert(id)\n" + "assert(not activeKey)\n" + ); + + struct mScriptKeyEvent keyEvent = { + .d = { .type = mSCRIPT_EV_TYPE_KEY }, + .state = mSCRIPT_INPUT_STATE_DOWN, + .key = 'a' + }; + mScriptContextFireEvent(&context, &keyEvent.d); + + TEST_PROGRAM("assert(input:isKeyActive('a'))"); + TEST_PROGRAM("assert(activeKey == 'a')"); + TEST_PROGRAM("assert(state == C.INPUT_STATE.DOWN)"); + + keyEvent.state = mSCRIPT_INPUT_STATE_UP; + mScriptContextFireEvent(&context, &keyEvent.d); + + TEST_PROGRAM("assert(not input:isKeyActive('a'))"); + TEST_PROGRAM("assert(state == C.INPUT_STATE.UP)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(activeKeys) { + SETUP_LUA; + + TEST_PROGRAM("assert(#input:activeKeys() == 0)"); + + struct mScriptKeyEvent keyEvent = { + .d = { .type = mSCRIPT_EV_TYPE_KEY }, + .state = mSCRIPT_INPUT_STATE_DOWN, + .key = 'a' + }; + mScriptContextFireEvent(&context, &keyEvent.d); + TEST_PROGRAM("assert(#input:activeKeys() == 1)"); + TEST_PROGRAM("assert(input:activeKeys()[1] == string.byte('a'))"); + + keyEvent.state = mSCRIPT_INPUT_STATE_UP; + mScriptContextFireEvent(&context, &keyEvent.d); + + TEST_PROGRAM("assert(#input:activeKeys() == 0)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(clearKeys) { + SETUP_LUA; + + TEST_PROGRAM("assert(not input:isKeyActive('a'))"); + TEST_PROGRAM("assert(not input:isKeyActive('b'))"); + TEST_PROGRAM("assert(#input:activeKeys() == 0)"); + + struct mScriptKeyEvent keyEvent = { + .d = { .type = mSCRIPT_EV_TYPE_KEY }, + .state = mSCRIPT_INPUT_STATE_DOWN, + .key = 'a' + }; + mScriptContextFireEvent(&context, &keyEvent.d); + // This changes it to STATE_HELD, but increments the down counter + mScriptContextFireEvent(&context, &keyEvent.d); + keyEvent.state = mSCRIPT_INPUT_STATE_DOWN; + keyEvent.key = 'b'; + mScriptContextFireEvent(&context, &keyEvent.d); + + TEST_PROGRAM("assert(input:isKeyActive('a'))"); + TEST_PROGRAM("assert(input:isKeyActive('b'))"); + TEST_PROGRAM("assert(#input:activeKeys() == 2)"); + + TEST_PROGRAM( + "up = {}\n" + "function cb(ev)\n" + " assert(ev.type == C.EV_TYPE.KEY)\n" + " assert(ev.state == C.INPUT_STATE.UP)\n" + " table.insert(up, ev.key)\n" + "end\n" + "id = callbacks:add('key', cb)\n" + ); + + mScriptContextClearKeys(&context); + + TEST_PROGRAM("assert(not input:isKeyActive('a'))"); + TEST_PROGRAM("assert(not input:isKeyActive('b'))"); + TEST_PROGRAM("assert(#input:activeKeys() == 0)"); + TEST_PROGRAM("assert(#up == 2)"); + + mScriptContextDeinit(&context); +} + + +M_TEST_DEFINE(gamepadExport) { + SETUP_LUA; + + struct mScriptGamepad m_gamepad; + mScriptGamepadInit(&m_gamepad); + + TEST_PROGRAM("assert(not input.activeGamepad)"); + assert_int_equal(mScriptContextGamepadAttach(&context, &m_gamepad), 0); + TEST_PROGRAM("assert(input.activeGamepad)"); + + TEST_PROGRAM("assert(#input.activeGamepad.axes == 0)"); + TEST_PROGRAM("assert(#input.activeGamepad.buttons == 0)"); + TEST_PROGRAM("assert(#input.activeGamepad.hats == 0)"); + + mScriptGamepadSetAxisCount(&m_gamepad, 1); + TEST_PROGRAM("assert(#input.activeGamepad.axes == 1)"); + TEST_PROGRAM("assert(input.activeGamepad.axes[1] == 0)"); + mScriptGamepadSetAxis(&m_gamepad, 0, 123); + TEST_PROGRAM("assert(input.activeGamepad.axes[1] == 123)"); + + mScriptGamepadSetButtonCount(&m_gamepad, 1); + TEST_PROGRAM("assert(#input.activeGamepad.buttons == 1)"); + TEST_PROGRAM("assert(input.activeGamepad.buttons[1] == false)"); + mScriptGamepadSetButton(&m_gamepad, 0, true); + TEST_PROGRAM("assert(input.activeGamepad.buttons[1] == true)"); + + mScriptGamepadSetHatCount(&m_gamepad, 1); + TEST_PROGRAM("assert(#input.activeGamepad.hats == 1)"); + TEST_PROGRAM("assert(input.activeGamepad.hats[1] == C.INPUT_DIR.NONE)"); + mScriptGamepadSetHat(&m_gamepad, 0, mSCRIPT_INPUT_DIR_NORTHWEST); + TEST_PROGRAM("assert(input.activeGamepad.hats[1] == C.INPUT_DIR.NORTHWEST)"); + + mScriptContextGamepadDetach(&context, 0); + TEST_PROGRAM("assert(not input.activeGamepad)"); + + mScriptGamepadDeinit(&m_gamepad); + + mScriptContextDeinit(&context); +} + +M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput, + cmocka_unit_test(members), + cmocka_unit_test(seq), + cmocka_unit_test(fireKey), + cmocka_unit_test(activeKeys), + cmocka_unit_test(clearKeys), + cmocka_unit_test(gamepadExport), +) diff --git a/src/script/test/lua.c b/src/script/test/lua.c index 73954e91e..49c5521d7 100644 --- a/src/script/test/lua.c +++ b/src/script/test/lua.c @@ -22,6 +22,7 @@ struct Test { void (*vfn0)(struct Test*); void (*vfn1)(struct Test*, int); int32_t (*icfn0)(const struct Test*); + struct Test* next; }; static int identityInt(int in) { @@ -65,9 +66,14 @@ static int32_t sum(struct mScriptList* list) { return sum; } +static unsigned tableSize(struct Table* table) { + return TableSize(table); +} + mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32, a); mSCRIPT_BIND_FUNCTION(boundAddInts, S32, addInts, 2, S32, a, S32, b); mSCRIPT_BIND_FUNCTION(boundSum, S32, sum, 1, LIST, list); +mSCRIPT_BIND_FUNCTION(boundTableSize, U32, tableSize, 1, TABLE, table); mSCRIPT_DECLARE_STRUCT(Test); mSCRIPT_DECLARE_STRUCT_D_METHOD(Test, S32, ifn0, 0); @@ -83,6 +89,7 @@ mSCRIPT_DECLARE_STRUCT_VOID_METHOD(Test, v1, testV1, 1, S32, b); mSCRIPT_DEFINE_STRUCT(Test) mSCRIPT_DEFINE_STRUCT_MEMBER(Test, S32, i) + mSCRIPT_DEFINE_STRUCT_MEMBER(Test, PS(Test), next) mSCRIPT_DEFINE_STRUCT_METHOD(Test, ifn0) mSCRIPT_DEFINE_STRUCT_METHOD(Test, ifn1) mSCRIPT_DEFINE_STRUCT_METHOD(Test, icfn0) @@ -369,6 +376,71 @@ M_TEST_DEFINE(callCFunc) { assert_true(a.type->equal(&a, val)); mScriptValueDeref(val); + LOAD_PROGRAM("b('a')"); + assert_false(lua->run(lua)); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(callCTable) { + SETUP_LUA; + + assert_true(lua->setGlobal(lua, "b", &boundTableSize)); + + TEST_PROGRAM("assert(b({}) == 0)"); + assert_null(lua->getError(lua)); + + TEST_PROGRAM("assert(b({[2]=1}) == 1)"); + assert_null(lua->getError(lua)); + + TEST_PROGRAM("assert(b({a=1}) == 1)"); + assert_null(lua->getError(lua)); + + TEST_PROGRAM("assert(b({a={}}) == 1)"); + assert_null(lua->getError(lua)); + + LOAD_PROGRAM( + "a = {}\n" + "a.b = a\n" + "assert(b(a) == 1)\n" + ); + assert_false(lua->run(lua)); + + LOAD_PROGRAM( + "a = {}\n" + "a.b = {}\n" + "a.b.c = a\n" + "assert(b(a) == 1)\n" + ); + assert_false(lua->run(lua)); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(globalNull) { + SETUP_LUA; + + struct Test s = {}; + struct mScriptValue a; + + LOAD_PROGRAM("assert(a)"); + + a = mSCRIPT_MAKE_CHARP("hello"); + assert_true(lua->setGlobal(lua, "a", &a)); + assert_true(lua->run(lua)); + + a = mSCRIPT_MAKE_CHARP(NULL); + assert_true(lua->setGlobal(lua, "a", &a)); + assert_false(lua->run(lua)); + + a = mSCRIPT_MAKE_S(Test, &s); + assert_true(lua->setGlobal(lua, "a", &a)); + assert_true(lua->run(lua)); + + a = mSCRIPT_MAKE_S(Test, NULL); + assert_true(lua->setGlobal(lua, "a", &a)); + assert_false(lua->run(lua)); + mScriptContextDeinit(&context); } @@ -699,6 +771,84 @@ M_TEST_DEFINE(callList) { mScriptContextDeinit(&context); } +M_TEST_DEFINE(linkedList) { + SETUP_LUA; + + struct Test first = { + .i = 1 + }; + struct Test second = { + .i = 2 + }; + struct mScriptValue a = mSCRIPT_MAKE_S(Test, &first); + + assert_true(lua->setGlobal(lua, "l", &a)); + TEST_PROGRAM("assert(l)"); + TEST_PROGRAM("assert(l.i == 1)"); + TEST_PROGRAM("assert(not l.next)"); + + first.next = &second; + TEST_PROGRAM("assert(l)"); + TEST_PROGRAM("assert(l.i == 1)"); + TEST_PROGRAM("assert(l.next)"); + TEST_PROGRAM("assert(l.next.i == 2)"); + TEST_PROGRAM("assert(not l.next.next)"); + + TEST_PROGRAM( + "n = l.next\n" + "function readN()\n" + " assert(n)\n" + " assert(n.i or not n.i)\n" + "end\n" + "assert(pcall(readN))\n"); + // The weakref stored in `n` gets pruned between executions to avoid stale pointers + TEST_PROGRAM("assert(not pcall(readN))"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(listConvert) { + SETUP_LUA; + + struct mScriptValue* list = mScriptValueAlloc(mSCRIPT_TYPE_MS_LIST); + + assert_true(lua->setGlobal(lua, "l", list)); + TEST_PROGRAM("assert(l)"); + + struct mScriptValue* val = lua->getGlobal(lua, "l"); + assert_non_null(val); + if (val->type->base == mSCRIPT_TYPE_WRAPPER) { + val = mScriptValueUnwrap(val); + } + assert_ptr_equal(val->type, mSCRIPT_TYPE_MS_LIST); + assert_ptr_equal(val->value.list, list->value.list); + mScriptValueDeref(val); + mScriptValueDeref(list); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(tableConvert) { + SETUP_LUA; + + struct mScriptValue* list = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE); + + assert_true(lua->setGlobal(lua, "l", list)); + TEST_PROGRAM("assert(l)"); + + struct mScriptValue* val = lua->getGlobal(lua, "l"); + assert_non_null(val); + if (val->type->base == mSCRIPT_TYPE_WRAPPER) { + val = mScriptValueUnwrap(val); + } + assert_ptr_equal(val->type, mSCRIPT_TYPE_MS_TABLE); + assert_ptr_equal(val->value.table, list->value.table); + mScriptValueDeref(val); + mScriptValueDeref(list); + + mScriptContextDeinit(&context); +} + M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua, cmocka_unit_test(create), cmocka_unit_test(loadGood), @@ -709,6 +859,8 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua, cmocka_unit_test(rootScope), cmocka_unit_test(callLuaFunc), cmocka_unit_test(callCFunc), + cmocka_unit_test(callCTable), + cmocka_unit_test(globalNull), cmocka_unit_test(globalStructFieldGet), cmocka_unit_test(globalStructFieldSet), cmocka_unit_test(globalStructMethods), @@ -716,4 +868,7 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptLua, cmocka_unit_test(tableLookup), cmocka_unit_test(tableIterate), cmocka_unit_test(callList), + cmocka_unit_test(linkedList), + cmocka_unit_test(listConvert), + cmocka_unit_test(tableConvert), ) diff --git a/src/script/test/stdlib.c b/src/script/test/stdlib.c index 63ddda4fc..eda6deb7b 100644 --- a/src/script/test/stdlib.c +++ b/src/script/test/stdlib.c @@ -6,9 +6,7 @@ #include "util/test/suite.h" #include -#include -#include -#include +#include #include "script/test.h" @@ -82,22 +80,99 @@ M_TEST_DEFINE(callbacks) { TEST_VALUE(S32, "val", 0); - mScriptContextTriggerCallback(&context, "test"); + mScriptContextTriggerCallback(&context, "test", NULL); TEST_VALUE(S32, "val", 1); - mScriptContextTriggerCallback(&context, "test"); + mScriptContextTriggerCallback(&context, "test", NULL); TEST_VALUE(S32, "val", 2); TEST_PROGRAM("callbacks:remove(id)"); - mScriptContextTriggerCallback(&context, "test"); + mScriptContextTriggerCallback(&context, "test", NULL); TEST_VALUE(S32, "val", 2); mScriptContextDeinit(&context); } +M_TEST_DEFINE(oneshot) { + SETUP_LUA; + + TEST_PROGRAM( + "val = 0\n" + "function cb()\n" + " val = val + 1\n" + "end\n" + "id = callbacks:oneshot('test', cb)\n" + "assert(id)" + ); + + TEST_VALUE(S32, "val", 0); + + mScriptContextTriggerCallback(&context, "test", NULL); + TEST_VALUE(S32, "val", 1); + + mScriptContextTriggerCallback(&context, "test", NULL); + TEST_VALUE(S32, "val", 1); + + TEST_PROGRAM( + "id = callbacks:oneshot('test', cb)\n" + "assert(id)\n" + "callbacks:remove(id)" + ); + + mScriptContextTriggerCallback(&context, "test", NULL); + TEST_VALUE(S32, "val", 1); + + mScriptContextDeinit(&context); +} + +static void _tableIncrement(struct mScriptValue* table) { + assert_non_null(table); + struct mScriptValue* value = mScriptTableLookup(table, &mSCRIPT_MAKE_CHARP("key")); + assert_non_null(value); + assert_ptr_equal(value->type, mSCRIPT_TYPE_MS_S32); + ++value->value.s32; +} + +mSCRIPT_BIND_VOID_FUNCTION(tableIncrement, _tableIncrement, 1, WTABLE, table); + +M_TEST_DEFINE(callbackWeakref) { + SETUP_LUA; + + struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE); + struct mScriptList args; + mScriptListInit(&args, 1); + mScriptValueWrap(table, mScriptListAppend(&args)); + struct mScriptValue* lambda = mScriptLambdaCreate0(&tableIncrement, &args); + mScriptListDeinit(&args); + struct mScriptValue* weakref = mScriptContextMakeWeakref(&context, lambda); + mScriptContextAddCallback(&context, "test", weakref); + + struct mScriptValue* key = mScriptStringCreateFromUTF8("key"); + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S32); + value->value.s32 = 1; + mScriptTableInsert(table, key, value); + + mScriptContextTriggerCallback(&context, "test", NULL); + assert_int_equal(value->value.s32, 2); + + mScriptContextClearWeakref(&context, weakref->value.u32); + mScriptValueDeref(weakref); + + mScriptContextTriggerCallback(&context, "test", NULL); + assert_int_equal(value->value.s32, 2); + + mScriptValueDeref(table); + mScriptValueDeref(key); + mScriptValueDeref(value); + + mScriptContextDeinit(&context); +} + M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStdlib, cmocka_unit_test(bitMask), cmocka_unit_test(bitUnmask), cmocka_unit_test(callbacks), + cmocka_unit_test(oneshot), + cmocka_unit_test(callbackWeakref), ) diff --git a/src/script/test/storage.c b/src/script/test/storage.c new file mode 100644 index 000000000..14851318a --- /dev/null +++ b/src/script/test/storage.c @@ -0,0 +1,584 @@ +/* Copyright (c) 2013-2023 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 +#include + +#include "script/test.h" + +#define SETUP_LUA \ + struct mScriptContext context; \ + mScriptContextInit(&context); \ + struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \ + mScriptContextAttachStdlib(&context); \ + mScriptContextAttachStorage(&context); \ + char bucketPath[PATH_MAX]; \ + mScriptStorageGetBucketPath("xtest", bucketPath); \ + remove(bucketPath) + +M_TEST_SUITE_SETUP(mScriptStorage) { + if (mSCRIPT_ENGINE_LUA->init) { + mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_SUITE_TEARDOWN(mScriptStorage) { + if (mSCRIPT_ENGINE_LUA->deinit) { + mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_DEFINE(basicInt) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = 1"); + TEST_PROGRAM("assert(bucket.a == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(basicFloat) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = 0.5"); + TEST_PROGRAM("assert(bucket.a == 0.5)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(basicBool) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = true"); + TEST_PROGRAM("assert(bucket.a == true)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(basicNil) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = nil"); + TEST_PROGRAM("assert(bucket.a == nil)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(basicString) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = 'hello'"); + TEST_PROGRAM("assert(bucket.a == 'hello')"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(basicList) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = {1}"); + TEST_PROGRAM("assert(#bucket.a == 1)"); + TEST_PROGRAM("assert(bucket.a[1] == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(basicTable) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = {['a']=1}"); + TEST_PROGRAM("assert(#bucket.a == 1)"); + TEST_PROGRAM("assert(bucket.a.a == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(nullByteString) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM("bucket.a = 'a\\x00b'"); + TEST_PROGRAM("assert(bucket.a == 'a\\x00b')"); + TEST_PROGRAM("assert(#bucket.a == 3)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(structured) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM( + "bucket.a = {\n" + " ['a'] = 1,\n" + " ['b'] = {1},\n" + " ['c'] = {\n" + " ['d'] = 1\n" + " }\n" + "}" + ); + TEST_PROGRAM("assert(bucket.a)"); + TEST_PROGRAM("assert(bucket.a.a == 1)"); + TEST_PROGRAM("assert(#bucket.a.b == 1)"); + TEST_PROGRAM("assert(bucket.a.b[1] == 1)"); + TEST_PROGRAM("assert(#bucket.a.c == 1)"); + TEST_PROGRAM("assert(bucket.a.c.d == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(invalidObject) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + LOAD_PROGRAM("bucket.a = bucket"); + assert_false(lua->run(lua)); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeInt) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = 1"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":1\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeFloat) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = 0.5"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":0.5\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeBool) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = true"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":true\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeNil) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = nil"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":null\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeString) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = 'hello'"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":\"hello\"\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeList) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = {1, 2}"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":[\n\t\t1,\n\t\t2\n\t]\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeTable) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = {['b']=1}"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":{\n\t\t\"b\":1\n\t}\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(serializeNullByteString) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("bucket.a = 'a\\x00b'"); + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + ssize_t size = vf->size(vf); + char* buf = calloc(1, size + 1); + assert_int_equal(vf->read(vf, buf, size), size); + assert_string_equal(buf, "{\n\t\"a\":\"a\\u0000b\"\n}"); + free(buf); + vf->close(vf); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeInt) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":1}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeFloat) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":0.5}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a == 0.5)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeBool) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":true}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a == true)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeNil) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":null}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a == nil)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeString) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":\"hello\"}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a == 'hello')"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeList) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":[1,2]}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(#bucket.a == 2)"); + TEST_PROGRAM("assert(bucket.a[1] == 1)"); + TEST_PROGRAM("assert(bucket.a[2] == 2)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeTable) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":{\"b\":1}}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a.b == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeNullByteString) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{\"a\":\"a\\u0000b\"}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(bucket.a == 'a\\x00b')"); + TEST_PROGRAM("assert(bucket.a ~= 'a\\x00c')"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(deserializeError) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + + TEST_PROGRAM("assert(not bucket.a)"); + + static const char* json = "{a:1}"; + struct VFile* vf = VFileFromConstMemory(json, strlen(json)); + assert_false(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + TEST_PROGRAM("assert(not bucket.a)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(structuredRoundTrip) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + TEST_PROGRAM( + "bucket.a = {\n" + " ['a'] = 1,\n" + " ['b'] = {1},\n" + " ['c'] = {\n" + " ['d'] = 1\n" + " }\n" + "}" + ); + + struct VFile* vf = VFileOpen("test.json", O_CREAT | O_TRUNC | O_WRONLY); + assert_true(mScriptStorageSaveBucketVF(&context, "xtest", vf)); + + TEST_PROGRAM("bucket.a = nil") + TEST_PROGRAM("assert(not bucket.a)"); + + vf = VFileOpen("test.json", O_RDONLY); + assert_non_null(vf); + assert_true(mScriptStorageLoadBucketVF(&context, "xtest", vf)); + + TEST_PROGRAM("assert(bucket.a)"); + TEST_PROGRAM("assert(bucket.a.a == 1)"); + TEST_PROGRAM("assert(#bucket.a.b == 1)"); + TEST_PROGRAM("assert(bucket.a.b[1] == 1)"); + TEST_PROGRAM("assert(#bucket.a.c == 1)"); + TEST_PROGRAM("assert(bucket.a.c.d == 1)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(autoflush) { + SETUP_LUA; + + TEST_PROGRAM("bucket = storage:getBucket('xtest')"); + TEST_PROGRAM("assert(bucket)"); + TEST_PROGRAM("assert(not bucket.a)"); + + TEST_PROGRAM("bucket:enableAutoFlush(true)") + TEST_PROGRAM("bucket.a = 1"); + TEST_PROGRAM("storage:flushAll()"); + TEST_PROGRAM("assert(bucket:reload())") + TEST_PROGRAM("assert(bucket.a == 1)"); + + TEST_PROGRAM("bucket:enableAutoFlush(false)") + TEST_PROGRAM("bucket.a = 2"); + TEST_PROGRAM("storage:flushAll()"); + TEST_PROGRAM("assert(bucket:reload())") + TEST_PROGRAM("assert(bucket.a == 1)"); + + TEST_PROGRAM("bucket:enableAutoFlush(false)") + TEST_PROGRAM("bucket.a = 3"); + TEST_PROGRAM("storage:flushAll()"); + TEST_PROGRAM("bucket:enableAutoFlush(true)") + TEST_PROGRAM("storage:flushAll()"); + TEST_PROGRAM("assert(bucket:reload())") + TEST_PROGRAM("assert(bucket.a == 3)"); + + mScriptContextDeinit(&context); +} + +M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptStorage, + cmocka_unit_test(basicInt), + cmocka_unit_test(basicFloat), + cmocka_unit_test(basicBool), + cmocka_unit_test(basicNil), + cmocka_unit_test(basicString), + cmocka_unit_test(basicList), + cmocka_unit_test(basicTable), + cmocka_unit_test(nullByteString), + cmocka_unit_test(invalidObject), + cmocka_unit_test(structured), + cmocka_unit_test(serializeInt), + cmocka_unit_test(serializeFloat), + cmocka_unit_test(serializeBool), + cmocka_unit_test(serializeNil), + cmocka_unit_test(serializeString), + cmocka_unit_test(serializeList), + cmocka_unit_test(serializeTable), + cmocka_unit_test(serializeNullByteString), + cmocka_unit_test(deserializeInt), + cmocka_unit_test(deserializeFloat), + cmocka_unit_test(deserializeBool), + cmocka_unit_test(deserializeNil), + cmocka_unit_test(deserializeString), + cmocka_unit_test(deserializeList), + cmocka_unit_test(deserializeTable), + cmocka_unit_test(deserializeNullByteString), + cmocka_unit_test(deserializeError), + cmocka_unit_test(structuredRoundTrip), + cmocka_unit_test(autoflush), +) diff --git a/src/script/test/types.c b/src/script/test/types.c index 6ad38563a..5c66b3f76 100644 --- a/src/script/test/types.c +++ b/src/script/test/types.c @@ -5,9 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "util/test/suite.h" -#include -#include -#include +#include struct Test { int32_t a; @@ -76,6 +74,18 @@ static int isSequential(struct mScriptList* list) { return true; } +static bool isNullCharp(const char* arg) { + return !arg; +} + +static bool isNullStruct(struct Test* arg) { + return !arg; +} + +static void increment(struct Test* t) { + ++t->a; +} + mSCRIPT_BIND_FUNCTION(boundVoidOne, S32, voidOne, 0); mSCRIPT_BIND_VOID_FUNCTION(boundDiscard, discard, 1, S32, ignored); mSCRIPT_BIND_FUNCTION(boundIdentityInt, S32, identityInt, 1, S32, in); @@ -86,6 +96,15 @@ mSCRIPT_BIND_FUNCTION(boundAddInts, S32, addInts, 2, S32, a, S32, b); mSCRIPT_BIND_FUNCTION(boundSubInts, S32, subInts, 2, S32, a, S32, b); mSCRIPT_BIND_FUNCTION(boundIsHello, S32, isHello, 1, CHARP, str); mSCRIPT_BIND_FUNCTION(boundIsSequential, S32, isSequential, 1, LIST, list); +mSCRIPT_BIND_FUNCTION(boundIsNullCharp, BOOL, isNullCharp, 1, CHARP, arg); +mSCRIPT_BIND_FUNCTION(boundIsNullStruct, BOOL, isNullStruct, 1, S(Test), arg); +mSCRIPT_BIND_FUNCTION_WITH_DEFAULTS(boundAddIntWithDefaults, S32, addInts, 2, S32, a, S32, b); +mSCRIPT_BIND_VOID_FUNCTION(boundIncrement, increment, 1, S(Test), this); + +mSCRIPT_DEFINE_FUNCTION_BINDING_DEFAULTS(boundAddIntWithDefaults) + mSCRIPT_NO_DEFAULT, + mSCRIPT_S32(0) +mSCRIPT_DEFINE_DEFAULTS_END; M_TEST_DEFINE(voidArgs) { struct mScriptFrame frame; @@ -162,6 +181,30 @@ M_TEST_DEFINE(addS32) { mScriptFrameDeinit(&frame); } +M_TEST_DEFINE(addS32Defaults) { + struct mScriptFrame frame; + int32_t val; + + mScriptFrameInit(&frame); + mSCRIPT_PUSH(&frame.arguments, S32, 1); + mSCRIPT_PUSH(&frame.arguments, S32, 2); + assert_true(mScriptInvoke(&boundAddIntWithDefaults, &frame)); + assert_true(mScriptPopS32(&frame.returnValues, &val)); + assert_int_equal(val, 3); + mScriptFrameDeinit(&frame); + + mScriptFrameInit(&frame); + mSCRIPT_PUSH(&frame.arguments, S32, 1); + assert_true(mScriptInvoke(&boundAddIntWithDefaults, &frame)); + assert_true(mScriptPopS32(&frame.returnValues, &val)); + assert_int_equal(val, 1); + mScriptFrameDeinit(&frame); + + mScriptFrameInit(&frame); + assert_false(mScriptInvoke(&boundAddIntWithDefaults, &frame)); + mScriptFrameDeinit(&frame); +} + M_TEST_DEFINE(subS32) { struct mScriptFrame frame; mScriptFrameInit(&frame); @@ -1261,6 +1304,65 @@ M_TEST_DEFINE(invokeList) { mScriptListDeinit(&list); } +M_TEST_DEFINE(nullString) { + struct mScriptFrame frame; + bool res; + mScriptFrameInit(&frame); + + mSCRIPT_PUSH(&frame.arguments, CHARP, "hi"); + assert_true(mScriptInvoke(&boundIsNullCharp, &frame)); + assert_true(mScriptPopBool(&frame.returnValues, &res)); + assert_false(res); + + mSCRIPT_PUSH(&frame.arguments, CHARP, NULL); + assert_true(mScriptInvoke(&boundIsNullCharp, &frame)); + assert_true(mScriptPopBool(&frame.returnValues, &res)); + assert_true(res); + + mScriptFrameDeinit(&frame); +} + +M_TEST_DEFINE(nullStruct) { + struct mScriptFrame frame; + struct Test v = {}; + bool res; + mScriptFrameInit(&frame); + + mSCRIPT_PUSH(&frame.arguments, S(Test), &v); + assert_true(mScriptInvoke(&boundIsNullStruct, &frame)); + assert_true(mScriptPopBool(&frame.returnValues, &res)); + assert_false(res); + + mSCRIPT_PUSH(&frame.arguments, S(Test), NULL); + assert_true(mScriptInvoke(&boundIsNullStruct, &frame)); + assert_true(mScriptPopBool(&frame.returnValues, &res)); + assert_true(res); + + mScriptFrameDeinit(&frame); +} + +M_TEST_DEFINE(lambda0) { + struct mScriptList args; + struct Test t = { + .a = 0 + }; + + mScriptListInit(&args, 1); + mSCRIPT_PUSH(&args, S(Test), &t); + struct mScriptValue* fn = mScriptLambdaCreate0(&boundIncrement, &args); + assert_non_null(fn); + mScriptListDeinit(&args); + + struct mScriptFrame frame; + mScriptFrameInit(&frame); + assert_int_equal(t.a, 0); + assert_true(mScriptInvoke(fn, &frame)); + assert_int_equal(t.a, 1); + mScriptFrameDeinit(&frame); + + mScriptValueDeref(fn); +} + M_TEST_SUITE_DEFINE(mScript, cmocka_unit_test(voidArgs), cmocka_unit_test(voidFunc), @@ -1269,6 +1371,7 @@ M_TEST_SUITE_DEFINE(mScript, cmocka_unit_test(identityFunctionF32), cmocka_unit_test(identityFunctionStruct), cmocka_unit_test(addS32), + cmocka_unit_test(addS32Defaults), cmocka_unit_test(subS32), cmocka_unit_test(wrongArgCountLo), cmocka_unit_test(wrongArgCountHi), @@ -1295,4 +1398,7 @@ M_TEST_SUITE_DEFINE(mScript, cmocka_unit_test(stringIsHello), cmocka_unit_test(stringIsNotHello), cmocka_unit_test(invokeList), + cmocka_unit_test(nullString), + cmocka_unit_test(nullStruct), + cmocka_unit_test(lambda0), ) diff --git a/src/script/types.c b/src/script/types.c index b63fed4a5..20f945839 100644 --- a/src/script/types.c +++ b/src/script/types.c @@ -5,12 +5,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include #include #include #include #include +struct mScriptLambda { + struct mScriptValue* fn; + struct mScriptList arguments; +}; + static void _allocList(struct mScriptValue*); static void _freeList(struct mScriptValue*); @@ -26,6 +32,10 @@ static bool _stringCast(const struct mScriptValue*, const struct mScriptType*, s static bool _castScalar(const struct mScriptValue*, const struct mScriptType*, struct mScriptValue*); static uint32_t _hashScalar(const struct mScriptValue*); +static bool _wstrCast(const struct mScriptValue*, const struct mScriptType*, struct mScriptValue*); +static bool _wlistCast(const struct mScriptValue*, const struct mScriptType*, struct mScriptValue*); +static bool _wtableCast(const struct mScriptValue*, const struct mScriptType*, struct mScriptValue*); + static uint32_t _valHash(const void* val, size_t len, uint32_t seed); static bool _valEqual(const void* a, const void* b); static void* _valRef(void*); @@ -42,6 +52,10 @@ static bool _boolEqual(const struct mScriptValue*, const struct mScriptValue*); static bool _charpEqual(const struct mScriptValue*, const struct mScriptValue*); static bool _stringEqual(const struct mScriptValue*, const struct mScriptValue*); +static void _lambdaAlloc(struct mScriptValue* val); +static void _lambdaFree(struct mScriptValue* val); +static bool _callLambda0(struct mScriptFrame* frame, void* context); + const struct mScriptType mSTVoid = { .base = mSCRIPT_TYPE_VOID, .size = 0, @@ -231,6 +245,7 @@ const struct mScriptType mSTStringWrapper = { .alloc = NULL, .free = NULL, .hash = NULL, + .cast = _wstrCast, }; const struct mScriptType mSTListWrapper = { @@ -240,6 +255,17 @@ const struct mScriptType mSTListWrapper = { .alloc = NULL, .free = NULL, .hash = NULL, + .cast = _wlistCast, +}; + +const struct mScriptType mSTTableWrapper = { + .base = mSCRIPT_TYPE_WRAPPER, + .size = sizeof(struct mScriptValue), + .name = "wrapper table", + .alloc = NULL, + .free = NULL, + .hash = NULL, + .cast = _wtableCast, }; const struct mScriptType mSTWeakref = { @@ -251,6 +277,25 @@ const struct mScriptType mSTWeakref = { .hash = NULL, }; +const struct mScriptType mSTLambda0 = { + .base = mSCRIPT_TYPE_FUNCTION, + .size = sizeof(struct mScriptLambda), + .name = "lambda", + .details = { + .function = { + .parameters = { + .count = 0, + }, + .returnType = { + .count = 0, + }, + }, + }, + .alloc = _lambdaAlloc, + .free = _lambdaFree, + .hash = NULL, +}; + struct mScriptValue mScriptValueNull = { .type = &mSTVoid, .refs = mSCRIPT_VALUE_UNREF @@ -347,22 +392,43 @@ static uint32_t _hashString(const struct mScriptValue* val) { return hash32(buffer, size, 0); } -uint32_t _hashScalar(const struct mScriptValue* val) { - // From https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key - uint32_t x = 0; - switch (val->type->base) { - case mSCRIPT_TYPE_SINT: - x = val->value.s32; - break; - case mSCRIPT_TYPE_UINT: - default: - x = val->value.u32; - break; +bool _wstrCast(const struct mScriptValue* input, const struct mScriptType* type, struct mScriptValue* output) { + if (input->type->base != mSCRIPT_TYPE_WRAPPER) { + return false; } - x = ((x >> 16) ^ x) * 0x45D9F3B; - x = ((x >> 16) ^ x) * 0x45D9F3B; - x = (x >> 16) ^ x; - return x; + const struct mScriptValue* unwrapped = mScriptValueUnwrapConst(input); + if (unwrapped->type != mSCRIPT_TYPE_MS_STR) { + return false; + } + memcpy(output, input, sizeof(*output)); + output->type = type; + return true; +} + +bool _wlistCast(const struct mScriptValue* input, const struct mScriptType* type, struct mScriptValue* output) { + if (input->type->base != mSCRIPT_TYPE_WRAPPER) { + return false; + } + const struct mScriptValue* unwrapped = mScriptValueUnwrapConst(input); + if (unwrapped->type != mSCRIPT_TYPE_MS_LIST) { + return false; + } + memcpy(output, input, sizeof(*output)); + output->type = type; + return true; +} + +bool _wtableCast(const struct mScriptValue* input, const struct mScriptType* type, struct mScriptValue* output) { + if (input->type->base != mSCRIPT_TYPE_WRAPPER) { + return false; + } + const struct mScriptValue* unwrapped = mScriptValueUnwrapConst(input); + if (unwrapped->type != mSCRIPT_TYPE_MS_TABLE) { + return false; + } + memcpy(output, input, sizeof(*output)); + output->type = type; + return true; } #define AS(NAME, TYPE) \ @@ -463,6 +529,16 @@ bool _castScalar(const struct mScriptValue* input, const struct mScriptType* typ return true; } +uint32_t _hashScalar(const struct mScriptValue* val) { + // From https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + uint32_t x = 0; + _asUInt32(val, &x); + x = ((x >> 16) ^ x) * 0x45D9F3B; + x = ((x >> 16) ^ x) * 0x45D9F3B; + x = (x >> 16) ^ x; + return x; +} + uint32_t _valHash(const void* val, size_t len, uint32_t seed) { UNUSED(len); const struct mScriptValue* value = val; @@ -778,6 +854,32 @@ bool _stringEqual(const struct mScriptValue* a, const struct mScriptValue* b) { return strncmp(valA, valB, lenA) == 0; } +void _lambdaAlloc(struct mScriptValue* value) { + struct mScriptLambda* lambda = calloc(1, sizeof(*lambda)); + struct mScriptFunction* fn = calloc(1, sizeof(*fn)); + fn->context = lambda; + mScriptListInit(&lambda->arguments, 0); + value->value.opaque = fn; +} + +void _lambdaFree(struct mScriptValue* value) { + struct mScriptFunction* fn = value->value.opaque; + struct mScriptLambda* lambda = fn->context; + size_t i; + for (i = 0; i < mScriptListSize(&lambda->arguments); ++i) { + struct mScriptValue* val = mScriptListGetPointer(&lambda->arguments, i); + if (val->type->base != mSCRIPT_TYPE_WRAPPER) { + continue; + } + val = mScriptValueUnwrap(val); + mScriptValueDeref(val); + } + mScriptListDeinit(&lambda->arguments); + mScriptValueDeref(lambda->fn); + free(lambda); + free(fn); +} + struct mScriptValue* mScriptValueAlloc(const struct mScriptType* type) { // TODO: Use an arena instead of just the generic heap struct mScriptValue* val = malloc(sizeof(*val)); @@ -835,13 +937,12 @@ void mScriptValueWrap(struct mScriptValue* value, struct mScriptValue* out) { } out->type = mSCRIPT_TYPE_MS_WRAPPER; - out->value.opaque = value; - mScriptValueRef(value); + out->value.wrapped = value; } struct mScriptValue* mScriptValueUnwrap(struct mScriptValue* value) { if (value->type->base == mSCRIPT_TYPE_WRAPPER) { - return value->value.opaque; + return value->value.wrapped; } return NULL; } @@ -853,6 +954,21 @@ const struct mScriptValue* mScriptValueUnwrapConst(const struct mScriptValue* va return NULL; } +void mScriptValueFollowPointer(struct mScriptValue* ptr, struct mScriptValue* out) { + if (ptr->type->base != mSCRIPT_TYPE_OPAQUE || !ptr->type->details.type) { + return; + } + + out->value.opaque = *(void**) ptr->value.opaque; + if (out->value.opaque) { + out->type = ptr->type->details.type; + } else { + out->type = mSCRIPT_TYPE_MS_VOID; + } + out->refs = mSCRIPT_VALUE_UNREF; + out->flags = 0; +} + struct mScriptValue* mScriptStringCreateEmpty(size_t size) { struct mScriptValue* val = mScriptValueAlloc(mSCRIPT_TYPE_MS_STR); struct mScriptString* internal = val->value.opaque; @@ -928,14 +1044,11 @@ bool mScriptTableRemove(struct mScriptValue* table, struct mScriptValue* key) { } struct mScriptValue* mScriptTableLookup(struct mScriptValue* table, struct mScriptValue* key) { - if (table->type->base == mSCRIPT_TYPE_WRAPPER) { - table = mScriptValueUnwrap(table); - } if (table->type != mSCRIPT_TYPE_MS_TABLE) { - return false; + return NULL; } if (!key->type->hash) { - return false; + return NULL; } return HashTableLookupCustom(table->value.table, key); } @@ -1015,6 +1128,44 @@ void mScriptFrameDeinit(struct mScriptFrame* frame) { mScriptListDeinit(&frame->arguments); } +struct mScriptValue* mScriptLambdaCreate0(struct mScriptValue* fn, struct mScriptList* args) { + struct mScriptValue* value = mScriptValueAlloc(&mSTLambda0); + struct mScriptFunction* lfn = value->value.opaque; + struct mScriptLambda* lambda = lfn->context; + lfn->call = _callLambda0; + lambda->fn = fn; + mScriptValueRef(fn); + if (args) { + mScriptListCopy(&lambda->arguments, args); + size_t i; + for (i = 0; i < mScriptListSize(args); ++i) { + struct mScriptValue* val = mScriptListGetPointer(args, i); + if (val->type->base != mSCRIPT_TYPE_WRAPPER) { + continue; + } + val = mScriptValueUnwrap(val); + mScriptValueRef(val); + } + } + return value; +} + +bool _callLambda0(struct mScriptFrame* frame, void* context) { + if (mScriptListSize(&frame->arguments)) { + return false; + } + struct mScriptLambda* lambda = context; + struct mScriptFrame subframe; + mScriptFrameInit(&subframe); + mScriptListCopy(&subframe.arguments, &lambda->arguments); + bool ok = mScriptInvoke(lambda->fn, &subframe); + if (mScriptListSize(&subframe.returnValues)) { + ok = false; + } + mScriptFrameDeinit(&subframe); + return ok; +} + static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScriptClassInitDetails* details, bool child) { const char* docstring = NULL; @@ -1081,12 +1232,16 @@ static void _mScriptClassInit(struct mScriptTypeClass* cls, const struct mScript } break; case mSCRIPT_CLASS_INIT_SET: - cls->set = calloc(1, sizeof(*member)); - memcpy(cls->set, &detail->info.member, sizeof(*member)); + member = calloc(1, sizeof(*member)); + memcpy(member, &detail->info.member, sizeof(*member)); if (docstring) { - cls->set->docstring = docstring; + member->docstring = docstring; docstring = NULL; } + if (detail->info.member.type->details.function.parameters.count != 3) { + abort(); + } + HashTableInsert(&cls->setters, detail->info.member.type->details.function.parameters.entries[2]->name, member); break; case mSCRIPT_CLASS_INIT_INTERNAL: cls->internal = true; @@ -1101,11 +1256,11 @@ void mScriptClassInit(struct mScriptTypeClass* cls) { } HashTableInit(&cls->instanceMembers, 0, free); HashTableInit(&cls->castToMembers, 0, NULL); + HashTableInit(&cls->setters, 0, free); cls->alloc = NULL; cls->free = NULL; cls->get = NULL; - cls->set = NULL; _mScriptClassInit(cls, cls->details, false); cls->init = true; @@ -1117,6 +1272,7 @@ void mScriptClassDeinit(struct mScriptTypeClass* cls) { } HashTableDeinit(&cls->instanceMembers); HashTableDeinit(&cls->castToMembers); + HashTableDeinit(&cls->setters); cls->init = false; } @@ -1178,6 +1334,21 @@ static bool _accessRawMember(struct mScriptClassMember* member, void* raw, bool val->type = mSCRIPT_TYPE_MS_WRAPPER; val->value.table = raw; break; + case mSCRIPT_TYPE_STRING: + if (member->type == mSCRIPT_TYPE_MS_CHARP) { + val->refs = mSCRIPT_VALUE_UNREF; + val->flags = 0; + val->type = mSCRIPT_TYPE_MS_CHARP; + val->value.opaque = raw; + break; + } + return false; + case mSCRIPT_TYPE_LIST: + val->refs = mSCRIPT_VALUE_UNREF; + val->flags = 0; + val->type = mSCRIPT_TYPE_MS_LIST; + val->value.list = raw; + break; case mSCRIPT_TYPE_FUNCTION: val->refs = mSCRIPT_VALUE_UNREF; val->flags = 0; @@ -1234,7 +1405,7 @@ bool mScriptObjectGet(struct mScriptValue* obj, const char* member, struct mScri this->type = obj->type; this->refs = mSCRIPT_VALUE_UNREF; this->flags = 0; - this->value.opaque = obj; + this->value.opaque = obj->value.opaque; mSCRIPT_PUSH(&frame.arguments, CHARP, member); if (!mScriptInvoke(&getMember, &frame) || mScriptListSize(&frame.returnValues) != 1) { mScriptFrameDeinit(&frame); @@ -1269,6 +1440,91 @@ bool mScriptObjectGetConst(const struct mScriptValue* obj, const char* member, s return _accessRawMember(m, obj->value.opaque, true, val); } +static struct mScriptClassMember* _findSetter(const struct mScriptTypeClass* cls, const struct mScriptType* type) { + struct mScriptClassMember* m = HashTableLookup(&cls->setters, type->name); + if (m) { + return m; + } + + switch (type->base) { + case mSCRIPT_TYPE_SINT: + if (type->size < 2) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_S16->name); + if (m) { + return m; + } + } + if (type->size < 4) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_S32->name); + if (m) { + return m; + } + } + if (type->size < 8) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_S64->name); + if (m) { + return m; + } + } + break; + case mSCRIPT_TYPE_UINT: + if (type->size < 2) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_U16->name); + if (m) { + return m; + } + } + if (type->size < 4) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_U32->name); + if (m) { + return m; + } + } + if (type->size < 8) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_U64->name); + if (m) { + return m; + } + } + break; + case mSCRIPT_TYPE_FLOAT: + if (type->size < 8) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_F64->name); + if (m) { + return m; + } + } + break; + case mSCRIPT_TYPE_STRING: + if (type == mSCRIPT_TYPE_MS_STR) { + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_CHARP->name); + if (m) { + return m; + } + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_WSTR->name); + if (m) { + return m; + } + } + break; + case mSCRIPT_TYPE_LIST: + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_WLIST->name); + if (m) { + return m; + } + break; + case mSCRIPT_TYPE_TABLE: + m = HashTableLookup(&cls->setters, mSCRIPT_TYPE_MS_WTABLE->name); + if (m) { + return m; + } + break; + default: + break; + } + return NULL; +} + bool mScriptObjectSet(struct mScriptValue* obj, const char* member, struct mScriptValue* val) { if (obj->type->base != mSCRIPT_TYPE_OBJECT || obj->type->isConst) { return false; @@ -1283,6 +1539,32 @@ bool mScriptObjectSet(struct mScriptValue* obj, const char* member, struct mScri struct mScriptClassMember* m = HashTableLookup(&cls->instanceMembers, member); if (!m) { + if (val->type->base == mSCRIPT_TYPE_WRAPPER) { + val = mScriptValueUnwrap(val); + } + struct mScriptValue setMember; + m = _findSetter(cls, val->type); + if (!m || !_accessRawMember(m, obj->value.opaque, obj->type->isConst, &setMember)) { + return false; + } + struct mScriptFrame frame; + mScriptFrameInit(&frame); + struct mScriptValue* this = mScriptListAppend(&frame.arguments); + this->type = obj->type; + this->refs = mSCRIPT_VALUE_UNREF; + this->flags = 0; + this->value.opaque = obj->value.opaque; + mSCRIPT_PUSH(&frame.arguments, CHARP, member); + mScriptValueWrap(val, mScriptListAppend(&frame.arguments)); + if (!mScriptInvoke(&setMember, &frame) || mScriptListSize(&frame.returnValues) != 0) { + mScriptFrameDeinit(&frame); + return false; + } + mScriptFrameDeinit(&frame); + return true; + } + + if (m->readonly) { return false; } @@ -1378,26 +1660,58 @@ void mScriptObjectFree(struct mScriptValue* value) { if (value->type->base != mSCRIPT_TYPE_OBJECT) { return; } - if (value->flags & mSCRIPT_VALUE_FLAG_FREE_BUFFER) { + if (value->flags & (mSCRIPT_VALUE_FLAG_DEINIT | mSCRIPT_VALUE_FLAG_FREE_BUFFER)) { mScriptClassInit(value->type->details.cls); if (value->type->details.cls->free) { struct mScriptValue deinitMember; if (_accessRawMember(value->type->details.cls->free, value->value.opaque, value->type->isConst, &deinitMember)) { struct mScriptFrame frame; mScriptFrameInit(&frame); - struct mScriptValue* this = mScriptListAppend(&frame.arguments); - this->type = mSCRIPT_TYPE_MS_WRAPPER; - this->refs = mSCRIPT_VALUE_UNREF; - this->flags = 0; - this->value.opaque = value; + mSCRIPT_PUSH(&frame.arguments, WRAPPER, value); mScriptInvoke(&deinitMember, &frame); mScriptFrameDeinit(&frame); } } + } + if (value->flags & mSCRIPT_VALUE_FLAG_FREE_BUFFER) { free(value->value.opaque); } } +struct mScriptValue* mScriptObjectBindLambda(struct mScriptValue* obj, const char* member, struct mScriptList* args) { + if (obj->type->base != mSCRIPT_TYPE_OBJECT) { + return false; + } + + struct mScriptTypeClass* cls = obj->type->details.cls; + if (!cls) { + return false; + } + + mScriptClassInit(cls); + + struct mScriptList arguments; + struct mScriptValue fn; + if (!mScriptObjectGetConst(obj, member, &fn)) { + return NULL; + } + + mScriptListInit(&arguments, 0); + mScriptValueWrap(obj, mScriptListAppend(&arguments)); + if (args) { + size_t i; + for (i = 0; i < mScriptListSize(args); ++i) { + memcpy(mScriptListAppend(&arguments), mScriptListGetConstPointer(args, i), sizeof(struct mScriptValue)); + } + } + + struct mScriptValue* value = mScriptValueAlloc(fn.type); + struct mScriptValue* lambda = mScriptLambdaCreate0(value, &arguments); + mScriptValueDeref(value); + mScriptListDeinit(&arguments); + return lambda; +} + bool mScriptPopS32(struct mScriptList* list, int32_t* out) { mSCRIPT_POP(list, S32, val); *out = val; @@ -1447,7 +1761,7 @@ bool mScriptPopPointer(struct mScriptList* list, void** out) { } bool mScriptCast(const struct mScriptType* type, const struct mScriptValue* input, struct mScriptValue* output) { - if (input->type->base == mSCRIPT_TYPE_WRAPPER) { + if (input->type->base == mSCRIPT_TYPE_WRAPPER && type->base != mSCRIPT_TYPE_WRAPPER) { input = mScriptValueUnwrapConst(input); } if (type->cast && type->cast(input, type, output)) { @@ -1474,7 +1788,11 @@ bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList struct mScriptValue* unwrapped = NULL; if (mScriptListGetPointer(frame, i)->type->base == mSCRIPT_TYPE_WRAPPER) { unwrapped = mScriptValueUnwrap(mScriptListGetPointer(frame, i)); - if (types->entries[i] == unwrapped->type) { + if (types->entries[i]->base == mSCRIPT_TYPE_WRAPPER) { + if (types->entries[i]->details.type == unwrapped->type) { + continue; + } + } else if (types->entries[i] == unwrapped->type) { continue; } } @@ -1494,3 +1812,56 @@ bool mScriptCoerceFrame(const struct mScriptTypeTuple* types, struct mScriptList } return true; } + +static void addTypesFromTuple(struct Table* types, const struct mScriptTypeTuple* tuple) { + size_t i; + for (i = 0; i < tuple->count; ++i) { + mScriptTypeAdd(types, tuple->entries[i]); + } +} + +static void addTypesFromTable(struct Table* types, struct Table* table) { + struct TableIterator iter; + if (!HashTableIteratorStart(table, &iter)) { + return; + } + do { + struct mScriptClassMember* member = HashTableIteratorGetValue(table, &iter); + mScriptTypeAdd(types, member->type); + } while(HashTableIteratorNext(table, &iter)); +} + +void mScriptTypeAdd(struct Table* types, const struct mScriptType* type) { + if (HashTableLookup(types, type->name) || type->isConst) { + return; + } + HashTableInsert(types, type->name, (struct mScriptType*) type); + switch (type->base) { + case mSCRIPT_TYPE_FUNCTION: + addTypesFromTuple(types, &type->details.function.parameters); + addTypesFromTuple(types, &type->details.function.returnType); + break; + case mSCRIPT_TYPE_OBJECT: + mScriptClassInit(type->details.cls); + if (type->details.cls->parent) { + mScriptTypeAdd(types, type->details.cls->parent); + } + addTypesFromTable(types, &type->details.cls->instanceMembers); + break; + case mSCRIPT_TYPE_OPAQUE: + case mSCRIPT_TYPE_WRAPPER: + if (type->details.type) { + mScriptTypeAdd(types, type->details.type); + } + case mSCRIPT_TYPE_VOID: + case mSCRIPT_TYPE_SINT: + case mSCRIPT_TYPE_UINT: + case mSCRIPT_TYPE_FLOAT: + case mSCRIPT_TYPE_STRING: + case mSCRIPT_TYPE_LIST: + case mSCRIPT_TYPE_TABLE: + case mSCRIPT_TYPE_WEAKREF: + // No subtypes + break; + } +} diff --git a/src/sm83/debugger/cli-debugger.c b/src/sm83/debugger/cli-debugger.c index dfc56dc23..fd5a3084d 100644 --- a/src/sm83/debugger/cli-debugger.c +++ b/src/sm83/debugger/cli-debugger.c @@ -26,7 +26,7 @@ static inline void _printFlags(struct CLIDebuggerBackend* be, union FlagRegister } static void _disassemble(struct CLIDebuggerSystem* debugger, struct CLIDebugVector* dv) { - struct SM83Core* cpu = debugger->p->d.core->cpu; + struct SM83Core* cpu = debugger->p->d.p->core->cpu; uint16_t address; int segment = -1; @@ -64,7 +64,7 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address uint8_t instruction; size_t bytesRemaining = 1; for (bytesRemaining = 1; bytesRemaining; --bytesRemaining) { - instruction = debugger->d.core->rawRead8(debugger->d.core, address, segment); + instruction = debugger->d.p->core->rawRead8(debugger->d.p->core, address, segment); disPtr += snprintf(disPtr, sizeof(disassembly) - (disPtr - disassembly), "%02X", instruction); ++address; bytesRemaining += SM83Decode(instruction, &info); @@ -78,16 +78,16 @@ static inline uint16_t _printLine(struct CLIDebugger* debugger, uint16_t address static void _printStatus(struct CLIDebuggerSystem* debugger) { struct CLIDebuggerBackend* be = debugger->p->backend; - struct SM83Core* cpu = debugger->p->d.core->cpu; + struct SM83Core* cpu = debugger->p->d.p->core->cpu; be->printf(be, "A: %02X F: %02X (AF: %04X)\n", cpu->a, cpu->f.packed, cpu->af); be->printf(be, "B: %02X C: %02X (BC: %04X)\n", cpu->b, cpu->c, cpu->bc); be->printf(be, "D: %02X E: %02X (DE: %04X)\n", cpu->d, cpu->e, cpu->de); be->printf(be, "H: %02X L: %02X (HL: %04X)\n", cpu->h, cpu->l, cpu->hl); be->printf(be, "PC: %04X SP: %04X\n", cpu->pc, cpu->sp); _printFlags(be, cpu->f); - be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.core->timing)); + be->printf(be, "T-cycle: %" PRIu64 "\n", mTimingGlobalTime(debugger->p->d.p->core->timing)); - struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.platform; + struct SM83Debugger* platDebugger = (struct SM83Debugger*) debugger->p->d.p->platform; size_t i; for (i = 0; platDebugger->segments[i].name; ++i) { be->printf(be, "%s%s: %02X", i ? " " : "", platDebugger->segments[i].name, cpu->memory.currentSegment(cpu, platDebugger->segments[i].start)); diff --git a/src/sm83/debugger/debugger.c b/src/sm83/debugger/debugger.c index f6a6f690e..162b044df 100644 --- a/src/sm83/debugger/debugger.c +++ b/src/sm83/debugger/debugger.c @@ -25,16 +25,18 @@ static struct mBreakpoint* _lookupBreakpoint(struct mBreakpointList* breakpoints return NULL; } -static void _destroyBreakpoint(struct mBreakpoint* breakpoint) { +static void _destroyBreakpoint(struct mDebugger* debugger, struct mBreakpoint* breakpoint) { if (breakpoint->condition) { parseFree(breakpoint->condition); } + TableRemove(&debugger->pointOwner, breakpoint->id); } -static void _destroyWatchpoint(struct mWatchpoint* watchpoint) { +static void _destroyWatchpoint(struct mDebugger* debugger, struct mWatchpoint* watchpoint) { if (watchpoint->condition) { parseFree(watchpoint->condition); } + TableRemove(&debugger->pointOwner, watchpoint->id); } static void SM83DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { @@ -52,7 +54,9 @@ static void SM83DebuggerCheckBreakpoints(struct mDebuggerPlatform* d) { } struct mDebuggerEntryInfo info = { .address = breakpoint->address, - .pointId = breakpoint->id + .segment = debugger->cpu->memory.currentSegment(debugger->cpu, breakpoint->address), + .pointId = breakpoint->id, + .target = TableLookup(&d->p->pointOwner, breakpoint->id) }; mDebuggerEnter(d->p, DEBUGGER_ENTER_BREAKPOINT, &info); } @@ -62,14 +66,15 @@ static void SM83DebuggerDeinit(struct mDebuggerPlatform* platform); static void SM83DebuggerEnter(struct mDebuggerPlatform* d, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info); -static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform*, const struct mBreakpoint*); -static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform*, struct mBreakpointList*); +static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform*, struct mDebuggerModule* owner, const struct mBreakpoint*); +static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform*, struct mDebuggerModule* owner, struct mBreakpointList*); static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform*, ssize_t id); -static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform*, const struct mWatchpoint*); -static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mWatchpointList*); +static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform*, struct mDebuggerModule* owner, const struct mWatchpoint*); +static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform*, struct mDebuggerModule* owner, struct mWatchpointList*); static void SM83DebuggerCheckBreakpoints(struct mDebuggerPlatform*); static bool SM83DebuggerHasBreakpoints(struct mDebuggerPlatform*); static void SM83DebuggerTrace(struct mDebuggerPlatform*, char* out, size_t* length); +static void SM83DebuggerNextInstructionInfo(struct mDebuggerPlatform* d, struct mDebuggerInstructionInfo* info); struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void) { struct SM83Debugger* platform = malloc(sizeof(struct SM83Debugger)); @@ -87,6 +92,7 @@ struct mDebuggerPlatform* SM83DebuggerPlatformCreate(void) { platform->d.getStackTraceMode = NULL; platform->d.setStackTraceMode = NULL; platform->d.updateStackTrace = NULL; + platform->d.nextInstructionInfo = SM83DebuggerNextInstructionInfo; platform->printStatus = NULL; return &platform->d; } @@ -104,12 +110,12 @@ void SM83DebuggerDeinit(struct mDebuggerPlatform* platform) { struct SM83Debugger* debugger = (struct SM83Debugger*) platform; size_t i; for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) { - _destroyBreakpoint(mBreakpointListGetPointer(&debugger->breakpoints, i)); + _destroyBreakpoint(debugger->d.p, mBreakpointListGetPointer(&debugger->breakpoints, i)); } mBreakpointListDeinit(&debugger->breakpoints); for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { - _destroyWatchpoint(mWatchpointListGetPointer(&debugger->watchpoints, i)); + _destroyWatchpoint(debugger->d.p, mWatchpointListGetPointer(&debugger->watchpoints, i)); } mWatchpointListDeinit(&debugger->watchpoints); } @@ -120,20 +126,16 @@ static void SM83DebuggerEnter(struct mDebuggerPlatform* platform, enum mDebugger struct SM83Debugger* debugger = (struct SM83Debugger*) platform; struct SM83Core* cpu = debugger->cpu; cpu->nextEvent = cpu->cycles; - - if (debugger->d.p->entered) { - debugger->d.p->entered(debugger->d.p, reason, info); - } } -static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform* d, const struct mBreakpoint* info) { +static ssize_t SM83DebuggerSetBreakpoint(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, const struct mBreakpoint* info) { struct SM83Debugger* debugger = (struct SM83Debugger*) d; struct mBreakpoint* breakpoint = mBreakpointListAppend(&debugger->breakpoints); *breakpoint = *info; breakpoint->id = debugger->nextId; + TableInsert(&debugger->d.p->pointOwner, breakpoint->id, owner); ++debugger->nextId; return breakpoint->id; - } static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) { @@ -144,7 +146,7 @@ static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) for (i = 0; i < mBreakpointListSize(breakpoints); ++i) { struct mBreakpoint* breakpoint = mBreakpointListGetPointer(breakpoints, i); if (breakpoint->id == id) { - _destroyBreakpoint(breakpoint); + _destroyBreakpoint(debugger->d.p, breakpoint); mBreakpointListShift(breakpoints, i, 1); return true; } @@ -154,7 +156,7 @@ static bool SM83DebuggerClearBreakpoint(struct mDebuggerPlatform* d, ssize_t id) for (i = 0; i < mWatchpointListSize(watchpoints); ++i) { struct mWatchpoint* watchpoint = mWatchpointListGetPointer(watchpoints, i); if (watchpoint->id == id) { - _destroyWatchpoint(watchpoint); + _destroyWatchpoint(debugger->d.p, watchpoint); mWatchpointListShift(watchpoints, i, 1); if (!mWatchpointListSize(&debugger->watchpoints)) { SM83DebuggerRemoveMemoryShim(debugger); @@ -170,7 +172,7 @@ static bool SM83DebuggerHasBreakpoints(struct mDebuggerPlatform* d) { return mBreakpointListSize(&debugger->breakpoints) || mWatchpointListSize(&debugger->watchpoints); } -static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const struct mWatchpoint* info) { +static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, const struct mWatchpoint* info) { struct SM83Debugger* debugger = (struct SM83Debugger*) d; if (!mWatchpointListSize(&debugger->watchpoints)) { SM83DebuggerInstallMemoryShim(debugger); @@ -178,20 +180,43 @@ static ssize_t SM83DebuggerSetWatchpoint(struct mDebuggerPlatform* d, const stru struct mWatchpoint* watchpoint = mWatchpointListAppend(&debugger->watchpoints); *watchpoint = *info; watchpoint->id = debugger->nextId; + TableInsert(&debugger->d.p->pointOwner, watchpoint->id, owner); ++debugger->nextId; return watchpoint->id; } -static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mBreakpointList* list) { +static void SM83DebuggerListBreakpoints(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, struct mBreakpointList* list) { struct SM83Debugger* debugger = (struct SM83Debugger*) d; mBreakpointListClear(list); - mBreakpointListCopy(list, &debugger->breakpoints); + if (owner) { + size_t i; + for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) { + struct mBreakpoint* point = mBreakpointListGetPointer(&debugger->breakpoints, i); + if (TableLookup(&debugger->d.p->pointOwner, point->id) != owner) { + continue; + } + memcpy(mBreakpointListAppend(list), point, sizeof(*point)); + } + } else { + mBreakpointListCopy(list, &debugger->breakpoints); + } } -static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mWatchpointList* list) { +static void SM83DebuggerListWatchpoints(struct mDebuggerPlatform* d, struct mDebuggerModule* owner, struct mWatchpointList* list) { struct SM83Debugger* debugger = (struct SM83Debugger*) d; mWatchpointListClear(list); - mWatchpointListCopy(list, &debugger->watchpoints); + if (owner) { + size_t i; + for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { + struct mWatchpoint* point = mWatchpointListGetPointer(&debugger->watchpoints, i); + if (TableLookup(&debugger->d.p->pointOwner, point->id) != owner) { + continue; + } + memcpy(mWatchpointListAppend(list), point, sizeof(*point)); + } + } else { + mWatchpointListCopy(list, &debugger->watchpoints); + } } static void SM83DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* length) { @@ -221,3 +246,21 @@ static void SM83DebuggerTrace(struct mDebuggerPlatform* d, char* out, size_t* le cpu->d, cpu->e, cpu->h, cpu->l, cpu->sp, cpu->memory.currentSegment(cpu, cpu->pc), cpu->pc, disassembly); } + +static void SM83DebuggerNextInstructionInfo(struct mDebuggerPlatform* d, struct mDebuggerInstructionInfo* info) { + struct SM83Debugger* debugger = (struct SM83Debugger*) d; + info->address = debugger->cpu->pc; + uint8_t opcode = debugger->cpu->memory.cpuLoad8(debugger->cpu, info->address); + info->width = SM83InstructionLength(opcode); + info->segment = debugger->cpu->memory.currentSegment(debugger->cpu, info->address); + info->flags[0] = mDebuggerAccessLogFlagsFillAccess8(0); + info->flags[1] = mDebuggerAccessLogFlagsFillAccess8(0); + info->flags[2] = mDebuggerAccessLogFlagsFillAccess8(0); + info->flagsEx[0] = mDebuggerAccessLogFlagsExFillExecuteOpcode(0); + info->flagsEx[1] = mDebuggerAccessLogFlagsExFillExecuteOperand(0); + info->flagsEx[2] = mDebuggerAccessLogFlagsExFillExecuteOperand(0); + if (info->width == 0) { + info->width = 1; + info->flagsEx[0] = mDebuggerAccessLogFlagsExFillErrorIllegalOpcode(info->flagsEx[0]); + } +} diff --git a/src/sm83/debugger/memory-debugger.c b/src/sm83/debugger/memory-debugger.c index 142ab92c7..a35c2afeb 100644 --- a/src/sm83/debugger/memory-debugger.c +++ b/src/sm83/debugger/memory-debugger.c @@ -12,7 +12,7 @@ #include -static bool _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint8_t newValue); +static void _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, enum mWatchpointType type, uint8_t newValue); #define FIND_DEBUGGER(DEBUGGER, CPU) \ do { \ @@ -32,17 +32,14 @@ static bool _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, s static RETURN DebuggerShim_ ## NAME TYPES { \ struct SM83Debugger* debugger; \ FIND_DEBUGGER(debugger, cpu); \ - struct mDebuggerEntryInfo info; \ - if (_checkWatchpoints(debugger, address, &info, WATCHPOINT_ ## RW, VALUE)) { \ - mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); \ - } \ + _checkWatchpoints(debugger, address, WATCHPOINT_ ## RW, VALUE); \ return debugger->originalMemory.NAME(cpu, __VA_ARGS__); \ } CREATE_WATCHPOINT_SHIM(load8, READ, 0, uint8_t, (struct SM83Core* cpu, uint16_t address), address) CREATE_WATCHPOINT_SHIM(store8, WRITE, value, void, (struct SM83Core* cpu, uint16_t address, int8_t value), address, value) -static bool _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, struct mDebuggerEntryInfo* info, enum mWatchpointType type, uint8_t newValue) { +static void _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, enum mWatchpointType type, uint8_t newValue) { struct mWatchpoint* watchpoint; size_t i; for (i = 0; i < mWatchpointListSize(&debugger->watchpoints); ++i) { @@ -59,16 +56,19 @@ static bool _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, s if ((watchpoint->type & WATCHPOINT_CHANGE) && newValue == oldValue) { continue; } - info->type.wp.oldValue = oldValue; - info->type.wp.newValue = newValue; - info->address = address; - info->type.wp.watchType = watchpoint->type; - info->type.wp.accessType = type; - info->pointId = watchpoint->id; - return true; + struct mDebuggerEntryInfo info; + info.type.wp.oldValue = oldValue; + info.type.wp.newValue = newValue; + info.type.wp.watchType = watchpoint->type; + info.type.wp.accessType = type; + info.address = address; + info.segment = debugger->originalMemory.currentSegment(debugger->cpu, address); + info.width = 1; + info.pointId = watchpoint->id; + info.target = TableLookup(&debugger->d.p->pointOwner, watchpoint->id); + mDebuggerEnter(debugger->d.p, DEBUGGER_ENTER_WATCHPOINT, &info); } } - return false; } void SM83DebuggerInstallMemoryShim(struct SM83Debugger* debugger) { diff --git a/src/sm83/decoder.c b/src/sm83/decoder.c index 819576c26..552187327 100644 --- a/src/sm83/decoder.c +++ b/src/sm83/decoder.c @@ -582,3 +582,27 @@ int SM83Disassemble(struct SM83InstructionInfo* info, uint16_t pc, char* buffer, buffer[blen - 1] = '\0'; return total; } + +static int _sm83Widths[256] = { + /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + /* 0 */ 1, 3, 1, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 1, 2, 1, + /* 1 */ 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + /* 2 */ 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + /* 3 */ 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, + /* 4 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 8 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 9 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* A */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* B */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* C */ 1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1, + /* D */ 1, 1, 3, 0, 3, 1, 2, 1, 1, 1, 3, 0, 3, 0, 2, 1, + /* E */ 2, 1, 1, 0, 0, 1, 2, 1, 2, 1, 3, 0, 0, 0, 2, 1, + /* F */ 2, 1, 1, 1, 0, 1, 2, 1, 2, 1, 3, 1, 0, 0, 2, 1, +}; + +int SM83InstructionLength(uint8_t opcode) { + return _sm83Widths[opcode]; +} diff --git a/src/sm83/sm83.c b/src/sm83/sm83.c index 00163a20b..9f14ab341 100644 --- a/src/sm83/sm83.c +++ b/src/sm83/sm83.c @@ -181,6 +181,9 @@ void SM83Tick(struct SM83Core* cpu) { cpu->irqh.processEvents(cpu); } _SM83TickInternal(cpu); + while (cpu->cycles >= cpu->nextEvent) { + cpu->irqh.processEvents(cpu); + } } void SM83Run(struct SM83Core* cpu) { diff --git a/src/script/docgen.c b/src/tools/docgen.c similarity index 89% rename from src/script/docgen.c rename to src/tools/docgen.c index 55d12eedc..f57fb8d44 100644 --- a/src/script/docgen.c +++ b/src/tools/docgen.c @@ -6,7 +6,8 @@ #include #include #include -#include +#include +#include #include struct mScriptContext context; @@ -36,62 +37,6 @@ void explainValue(struct mScriptValue* value, const char* name, int level); void explainValueScoped(struct mScriptValue* value, const char* name, const char* scope, int level); void explainType(struct mScriptType* type, int level); -void addTypesFromTuple(const struct mScriptTypeTuple*); -void addTypesFromTable(struct Table*); - -void addType(const struct mScriptType* type) { - if (HashTableLookup(&types, type->name) || type->isConst) { - return; - } - HashTableInsert(&types, type->name, (struct mScriptType*) type); - switch (type->base) { - case mSCRIPT_TYPE_FUNCTION: - addTypesFromTuple(&type->details.function.parameters); - addTypesFromTuple(&type->details.function.returnType); - break; - case mSCRIPT_TYPE_OBJECT: - mScriptClassInit(type->details.cls); - if (type->details.cls->parent) { - addType(type->details.cls->parent); - } - addTypesFromTable(&type->details.cls->instanceMembers); - break; - case mSCRIPT_TYPE_OPAQUE: - case mSCRIPT_TYPE_WRAPPER: - if (type->details.type) { - addType(type->details.type); - } - case mSCRIPT_TYPE_VOID: - case mSCRIPT_TYPE_SINT: - case mSCRIPT_TYPE_UINT: - case mSCRIPT_TYPE_FLOAT: - case mSCRIPT_TYPE_STRING: - case mSCRIPT_TYPE_LIST: - case mSCRIPT_TYPE_TABLE: - case mSCRIPT_TYPE_WEAKREF: - // No subtypes - break; - } -} - -void addTypesFromTuple(const struct mScriptTypeTuple* tuple) { - size_t i; - for (i = 0; i < tuple->count; ++i) { - addType(tuple->entries[i]); - } -} - -void addTypesFromTable(struct Table* table) { - struct TableIterator iter; - if (!HashTableIteratorStart(table, &iter)) { - return; - } - do { - struct mScriptClassMember* member = HashTableIteratorGetValue(table, &iter); - addType(member->type); - } while(HashTableIteratorNext(table, &iter)); -} - void printchomp(const char* string, int level) { char indent[(level + 1) * 2 + 1]; memset(indent, ' ', sizeof(indent) - 1); @@ -241,6 +186,9 @@ void explainClass(struct mScriptTypeClass* cls, int level) { } docstring = NULL; } + if (details->info.member.readonly) { + fprintf(out, "%s readonly: true\n", indent); + } fprintf(out, "%s type: %s\n", indent, details->info.member.type->name); break; case mSCRIPT_CLASS_INIT_END: @@ -265,7 +213,7 @@ void explainObject(struct mScriptValue* value, int level) { continue; } fprintf(out, "%s%s:\n", indent, details->info.member.name); - addType(details->info.member.type); + mScriptTypeAdd(&types, details->info.member.type); if (mScriptObjectGet(value, details->info.member.name, &member)) { struct mScriptValue* unwrappedMember; if (member.type->base == mSCRIPT_TYPE_WRAPPER) { @@ -288,7 +236,7 @@ void explainValueScoped(struct mScriptValue* value, const char* name, const char memset(indent, ' ', sizeof(indent) - 1); indent[sizeof(indent) - 1] = '\0'; value = mScriptContextAccessWeakref(&context, value); - addType(value->type); + mScriptTypeAdd(&types, value->type); fprintf(out, "%stype: %s\n", indent, value->type->name); const char* docstring = NULL; @@ -406,11 +354,7 @@ bool call(struct mScriptValue* obj, const char* method, struct mScriptFrame* fra if (!mScriptObjectGet(obj, method, &fn)) { return false; } - struct mScriptValue* this = mScriptListAppend(&frame->arguments); - this->type = mSCRIPT_TYPE_MS_WRAPPER; - this->refs = mSCRIPT_VALUE_UNREF; - this->flags = 0; - this->value.opaque = obj; + mSCRIPT_PUSH(&frame->arguments, WRAPPER, obj); return mScriptInvoke(&fn, frame); } @@ -421,7 +365,7 @@ void explainCore(struct mCore* core) { mScriptContextAttachCore(&context, core); struct mScriptValue* emu = mScriptContextGetGlobal(&context, "emu"); - addType(emu->type); + mScriptTypeAdd(&types, emu->type); if (mScriptObjectGet(emu, "memory", &wrapper)) { struct mScriptValue* memory = mScriptValueUnwrap(&wrapper); @@ -434,7 +378,7 @@ void explainCore(struct mCore* core) { fprintf(out, " %s:\n", name->value.string->buffer); value = mScriptContextAccessWeakref(&context, value); - addType(value->type); + mScriptTypeAdd(&types, value->type); struct mScriptFrame frame; uint32_t baseVal; @@ -486,7 +430,7 @@ void initTypes(void) { size_t i; for (i = 0; baseTypes[i]; ++i) { - addType(baseTypes[i]); + mScriptTypeAdd(&types, baseTypes[i]); } } @@ -522,10 +466,15 @@ int main(int argc, char* argv[]) { mScriptContextInit(&context); mScriptContextAttachStdlib(&context); + mScriptContextAttachCanvas(&context); + mScriptContextAttachImage(&context); + mScriptContextAttachInput(&context); mScriptContextAttachSocket(&context); + mScriptContextAttachStorage(&context); mScriptContextSetTextBufferFactory(&context, NULL, NULL); initTypes(); + mScriptContextGetInputTypes(&types); fputs("version:\n", out); fprintf(out, " string: \"%s\"\n", projectVersion); diff --git a/src/tools/font-sdf.c b/src/tools/font-sdf.c new file mode 100644 index 000000000..e28c34eaf --- /dev/null +++ b/src/tools/font-sdf.c @@ -0,0 +1,136 @@ +/* Copyright (c) 2013-2023 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 +#include +#include + +void createSdf(const struct mImage* src, struct mImage* dst, int x, int y, int w, int h) { + int i, j, ii, jj, z; + + static const int kernel[] = { + 11, 9, 8, 9, 11, + 9, 6, 4, 6, 9, + 8, 4, 0, 4, 8, + 9, 6, 4, 6, 9, + 11, 9, 8, 9, 11, + }; + const int* kc = &kernel[12]; + + for (j = y; j < y + h; ++j) { + for (i = x; i < x + w; ++i) { + if (mImageGetPixel(src, i, j) & 0xFFFFFF) { + mImageSetPixelRaw(dst, i, j, 0xFF); + } else { + mImageSetPixelRaw(dst, i, j, 1); + } + } + } + + for (z = 0; z < 16; ++z) { + int left = w * h; + for (j = y; j < y + h; ++j) { + for (i = x; i < x + w; ++i) { + int raw = mImageGetPixelRaw(dst, i, j) - 0x80; + int neighbors = raw; + for (jj = -2; jj < 3; ++jj) { + for (ii = -2; ii < 3; ++ii) { + if (!ii && !jj) { + continue; + } + if (i + ii - x < 0 || j + jj - y < 0) { + continue; + } + if (i + ii - x >= w || j + jj - y >= h) { + continue; + } + int neighbor = mImageGetPixelRaw(dst, i + ii, j + jj) - 0x80; + if (raw > 0) { + if (neighbor < 0) { + if ((!ii && (jj == -1 || jj == 1)) || (!jj && (ii == -1 || ii == 1))) { + neighbors = 1; + jj = 5; + break; + } + continue; + } + if (neighbor == 0x7F) { + continue; + } + if (neighbor + kc[ii + jj * 5] < neighbors) { + neighbors = neighbor + kc[ii + jj * 5]; + } + } else if (raw < 0) { + if (neighbor > 0) { + if ((!ii && (jj == -1 || jj == 1)) || (!jj && (ii == -1 || ii == 1))) { + neighbors = -4; + jj = 5; + break; + } + continue; + } + if (neighbor == -0x7F) { + continue; + } + if (neighbor - kc[ii + jj * 5] > neighbors) { + neighbors = neighbor - kc[ii + jj * 5]; + } + } + } + } + if (neighbors == raw) { + --left; + } else { + mImageSetPixelRaw(dst, i, j, neighbors + 0x80); + } + if (!left) { + break; + } + } + if (!left) { + break; + } + } + if (!left) { + break; + } + } +} + +int main(int argc, char* argv[]) { + struct mImage* source; + struct mImage* output; + + if (argc != 3) { + return 1; + } + source = mImageLoad(argv[1]); + if (!source) { + return 2; + } + output = mImageCreate(source->width, source->height, mCOLOR_L8); + if (!output) { + return 3; + } + + int i; + for (i = 0; i < 128; ++i) { + createSdf(source, output, (i & 0xF) << 6, (i & ~0xF) << 2, 64, 64); + } + for (i = 0; i < GUI_ICON_MAX; ++i) { + struct GUIIconMetric metric = defaultIconMetrics[i]; + metric.width += metric.x & 0xF; + metric.height += metric.y & 0xF; + metric.x &= ~0xF; + metric.y &= ~0xF; + createSdf(source, output, metric.x * 4, metric.y * 4 + 512, toPow2(metric.width) * 4, toPow2(metric.height) * 4); + } + if (!mImageSave(output, argv[2], NULL)) { + return 4; + } + mImageDestroy(source); + mImageDestroy(output); + return 0; +} diff --git a/src/feature/updater-main.c b/src/tools/updater-main.c similarity index 79% rename from src/feature/updater-main.c rename to src/tools/updater-main.c index bc29e5cd4..a27a07a08 100644 --- a/src/feature/updater-main.c +++ b/src/tools/updater-main.c @@ -21,6 +21,9 @@ #include #define mkdir(X, Y) _mkdir(X) +#ifndef S_ISDIR +#define S_ISDIR(MODE) (((MODE) & _S_IFMT) == _S_IFDIR) +#endif #elif defined(_POSIX_C_SOURCE) #include #endif @@ -31,6 +34,39 @@ FILE* logfile; +bool rmdirRecursive(struct VDir* dir) { + if (!dir) { + return false; + } + bool ok = true; + struct VDirEntry* vde; + while ((vde = dir->listNext(dir))) { + const char* name = vde->name(vde); + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + switch (vde->type(vde)) { + case VFS_DIRECTORY: + fprintf(logfile, "cd %s\n", name); + if (!rmdirRecursive(dir->openDir(dir, name))) { + ok = false; + } + fprintf(logfile, "cd ..\n"); + // Fall through + case VFS_FILE: + case VFS_UNKNOWN: + fprintf(logfile, "rm %s\n", name); + if (!dir->deleteFile(dir, name)) { + fprintf(logfile, "error\n"); + ok = false; + } + break; + } + } + dir->close(dir); + return ok; +} + bool extractArchive(struct VDir* archive, const char* root, bool prefix) { char path[PATH_MAX] = {0}; struct VDirEntry* vde; @@ -56,12 +92,32 @@ bool extractArchive(struct VDir* archive, const char* root, bool prefix) { switch (vde->type(vde)) { case VFS_DIRECTORY: fprintf(logfile, "mkdir %s\n", fname); - if (mkdir(path, 0755) < 0 && errno != EEXIST) { - return false; + if (mkdir(path, 0755) < 0) { + bool redo = true; + struct stat st; + if (errno != EEXIST || stat(path, &st) < 0) { + redo = false; + } else if (!S_ISDIR(st.st_mode)) { +#ifdef _WIN32 + wchar_t wpath[MAX_PATH + 1]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH); + DeleteFileW(wpath); +#else + unlink(path); +#endif + if (mkdir(path, 0755) < 0) { + redo = false; + } + } + if (!redo) { + fprintf(logfile, "error %i\n", errno); + return false; + } } if (!prefix) { struct VDir* subdir = archive->openDir(archive, fname); if (!subdir) { + fprintf(logfile, "error\n"); return false; } if (!extractArchive(subdir, path, false)) { @@ -76,13 +132,28 @@ bool extractArchive(struct VDir* archive, const char* root, bool prefix) { vfIn = archive->openFile(archive, vde->name(vde), O_RDONLY); errno = 0; vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); - if (!vfOut && errno == EACCES) { + if (!vfOut) { + if (errno == EACCES) { #ifdef _WIN32 - Sleep(1000); + Sleep(1000); #else - sleep(1); + sleep(1); #endif - vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + } else if (errno == EISDIR) { + fprintf(logfile, "rm -r %s\n", path); + if (!rmdirRecursive(VDirOpen(path))) { + return false; + } +#ifdef _WIN32 + wchar_t wpath[MAX_PATH + 1]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH); + RemoveDirectoryW(wpath); +#else + rmdir(path); +#endif + vfOut = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + } } if (!vfOut) { vfIn->close(vfIn); @@ -114,7 +185,7 @@ int main(int argc, char* argv[]) { int ok = 1; mCoreConfigDirectory(bin, sizeof(bin)); - strncat(bin, "/updater.log", sizeof(bin)); + strncat(bin, "/updater.log", sizeof(bin) - 1); logfile = fopen(bin, "w"); mCoreConfigInit(&config, "updater"); @@ -200,7 +271,7 @@ int main(int argc, char* argv[]) { // Cross-dev, need to copy manually int infd = open(updateArchive, O_RDONLY); int outfd = -1; - if (infd >= 0) { + if (infd < 0) { ok = 2; } else { outfd = open(bin, O_CREAT | O_WRONLY | O_TRUNC, 0755); @@ -274,7 +345,7 @@ int main(int argc, char* argv[]) { const char* argv[] = { qbin, NULL }; _execv(bin, argv); #elif defined(_POSIX_C_SOURCE) || defined(__APPLE__) - const char* argv[] = { bin, NULL }; + char* const argv[] = { bin, NULL }; execv(bin, argv); #endif } diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index df0d84c5c..eb82215d7 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -8,18 +8,21 @@ set(BASE_SOURCE_FILES hash.c string.c table.c + vector.c vfs.c) set(SOURCE_FILES ${BASE_SOURCE_FILES} convolve.c elf-read.c - export.c + geometry.c + image.c + image/export.c + image/png-io.c patch.c patch-fast.c patch-ips.c patch-ups.c - png-io.c ring-fifo.c sfo.c text-codec.c) @@ -32,6 +35,9 @@ set(GUI_FILES gui/menu.c) set(TEST_FILES + test/color.c + test/geometry.c + test/image.c test/sfo.c test/string-parser.c test/string-utf8.c diff --git a/src/util/geometry.c b/src/util/geometry.c new file mode 100644 index 000000000..17c523afe --- /dev/null +++ b/src/util/geometry.c @@ -0,0 +1,94 @@ +/* Copyright (c) 2013-2023 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 + +void mRectangleUnion(struct mRectangle* dst, const struct mRectangle* add) { + int x0 = dst->x; + int y0 = dst->y; + int x1 = dst->x + dst->width; + int y1 = dst->y + dst->height; + + if (add->x < x0) { + x0 = add->x; + } + if (add->y < y0) { + y0 = add->y; + } + if (add->x + add->width > x1) { + x1 = add->x + add->width; + } + if (add->y + add->height > y1) { + y1 = add->y + add->height; + } + + dst->x = x0; + dst->y = y0; + dst->width = x1 - x0; + dst->height = y1 - y0; +} + +bool mRectangleIntersection(struct mRectangle* dst, const struct mRectangle* add) { + int x[3]; + int y[3]; + + if (dst == add) { + return true; + } + +#define SORT(Z, M) \ + if (dst->Z < add->Z) { \ + Z[0] = dst->Z; \ + Z[1] = add->Z; \ + } else { \ + Z[0] = add->Z; \ + Z[1] = dst->Z; \ + } \ + if (dst->Z + dst->M < add->Z + add->M) { \ + /* dst is entirely before add */ \ + if (dst->Z + dst->M <= add->Z) { \ + return false; \ + } \ + if (dst->Z + dst->M < Z[1]) { \ + Z[2] = Z[1]; \ + Z[1] = dst->Z + dst->M; \ + } else { \ + Z[2] = dst->Z + dst->M; \ + } \ + if (add->Z + add->M < Z[2]) { \ + Z[2] = add->Z + add->M; \ + } \ + } else { \ + /* dst is after before add */ \ + if (dst->Z >= add->Z + add->M) { \ + return false; \ + } \ + if (add->Z + add->M < Z[1]) { \ + Z[2] = Z[1]; \ + Z[1] = add->Z + add->M; \ + } else { \ + Z[2] = add->Z + add->M; \ + } \ + if (dst->Z + dst->M < Z[2]) { \ + Z[2] = dst->Z + dst->M; \ + } \ + } + + SORT(x, width); + SORT(y, height); + +#undef SORT + + dst->x = x[1]; + dst->width = x[2] - x[1]; + dst->y = y[1]; + dst->height = y[2] - y[1]; + return true; +} + +void mRectangleCenter(const struct mRectangle* ref, struct mRectangle* rect) { + rect->x = ref->x + (ref->width - rect->width) / 2; + rect->y = ref->y + (ref->height - rect->height) / 2; +} diff --git a/src/util/image.c b/src/util/image.c new file mode 100644 index 000000000..a0fefafe7 --- /dev/null +++ b/src/util/image.c @@ -0,0 +1,1026 @@ +/* Copyright (c) 2013-2023 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 + +#include +#include +#include + +#define PIXEL(IM, X, Y) \ + (void*) (((IM)->stride * (Y) + (X)) * (IM)->depth + (uintptr_t) (IM)->data) + +#define ROW(IM, Y) PIXEL(IM, 0, Y) + +#ifdef __BIG_ENDIAN__ +#define SHIFT_IN(COLOR, DEPTH) \ + if ((DEPTH) < 4) { \ + (COLOR) >>= (32 - 8 * (DEPTH)); \ + } + +#define SHIFT_OUT(COLOR, DEPTH) \ + if ((DEPTH) < 4) { \ + (COLOR) <<= (32 - 8 *(DEPTH)); \ + } +#else +#define SHIFT_IN(COLOR, DEPTH) +#define SHIFT_OUT(COLOR, DEPTH) +#endif + +#define GET_PIXEL(DST, SRC, DEPTH) do { \ + uint32_t _color = 0; \ + memcpy(&_color, (void*) (SRC), (DEPTH)); \ + SHIFT_IN(_color, (DEPTH)); \ + (DST) = _color; \ +} while (0) + +#define PUT_PIXEL(SRC, DST, DEPTH) do { \ + uint32_t _color = (SRC); \ + SHIFT_OUT(_color, (DEPTH)); \ + memcpy((void*) (DST), &_color, (DEPTH)); \ +} while (0); + +struct mImage* mImageCreate(unsigned width, unsigned height, enum mColorFormat format) { + return mImageCreateWithStride(width, height, width, format); +} + +struct mImage* mImageCreateWithStride(unsigned width, unsigned height, unsigned stride, enum mColorFormat format) { + if (width < 1 || height < 1) { + return NULL; + } + struct mImage* image = calloc(1, sizeof(struct mImage)); + if (!image) { + return NULL; + } + image->width = width; + image->height = height; + image->stride = stride; + image->format = format; + image->depth = mColorFormatBytes(format); + image->data = calloc(width * height, image->depth); + if (!image->data) { + free(image); + return NULL; + } + if (format == mCOLOR_PAL8) { + image->palette = malloc(1024); + if (!image->palette) { + free(image->data); + free(image); + return NULL; + } + image->palSize = 1; + } + return image; +} + +struct mImage* mImageCreateFromConstBuffer(unsigned width, unsigned height, unsigned stride, enum mColorFormat format, const void* pixels) { + struct mImage* image = mImageCreateWithStride(width, height, stride, format); + if (!image) { + return NULL; + } + memcpy(image->data, pixels, height * stride * image->depth); + return image; +} + +struct mImage* mImageLoad(const char* path) { + struct VFile* vf = VFileOpen(path, O_RDONLY); + if (!vf) { + return NULL; + } + struct mImage* image = mImageLoadVF(vf); + vf->close(vf); + return image; +} + +#ifdef USE_PNG +static struct mImage* mImageLoadPNG(struct VFile* vf) { + png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES); + png_infop info = png_create_info_struct(png); + png_infop end = png_create_info_struct(png); + if (!png || !info || !end) { + PNGReadClose(png, info, end); + return NULL; + } + + if (!PNGReadHeader(png, info)) { + PNGReadClose(png, info, end); + return NULL; + } + unsigned width = png_get_image_width(png, info); + unsigned height = png_get_image_height(png, info); + + struct mImage* image = calloc(1, sizeof(*image)); + if (!image) { + PNGReadClose(png, info, end); + return NULL; + } + bool ok = true; + + image->width = width; + image->height = height; + image->stride = width; + + switch (png_get_channels(png, info)) { + case 3: + image->format = mCOLOR_XBGR8; + image->depth = 4; + image->data = malloc(width * height * 4); + if (!PNGReadPixels(png, info, image->data, width, height, width)) { + ok = false; + } + break; + case 4: + image->format = mCOLOR_ABGR8; + image->depth = 4; + image->data = malloc(width * height * 4); + if (!PNGReadPixelsA(png, info, image->data, width, height, width)) { + ok = false; + } + break; + case 1: + if (png_get_color_type(png, info) == PNG_COLOR_TYPE_GRAY) { + image->format = mCOLOR_L8; + } else { + png_colorp palette; + png_bytep trns; + int count; + int trnsCount = 0; + image->format = mCOLOR_PAL8; + if (png_get_PLTE(png, info, &palette, &count) == 0) { + ok = false; + break; + } + if (count > 256) { + count = 256; +#ifndef NDEBUG + abort(); +#endif + } + image->palette = malloc(1024); + image->palSize = count; + png_get_tRNS(png, info, &trns, &trnsCount, NULL); + + int i; + for (i = 0; i < count; ++i) { + uint32_t color = palette[i].red << 16; + color |= palette[i].green << 8; + color |= palette[i].blue; + + if (i < trnsCount) { + color |= trns[i] << 24; + } else { + color |= 0xFF000000; + } + image->palette[i] = color; + } + } + image->depth = 1; + image->data = malloc(width * height); + if (!PNGReadPixels8(png, info, image->data, width, height, width)) { + ok = false; + } + break; + default: + // Not supported yet + ok = false; + break; + } + + PNGReadClose(png, info, end); + if (!ok) { + mImageDestroy(image); + image = NULL; + } + return image; +} +#endif + +struct mImage* mImageLoadVF(struct VFile* vf) { + vf->seek(vf, 0, SEEK_SET); +#ifdef USE_PNG + if (isPNG(vf)) { + return mImageLoadPNG(vf); + } + vf->seek(vf, 0, SEEK_SET); +#endif + return NULL; +} + +struct mImage* mImageConvertToFormat(const struct mImage* image, enum mColorFormat format) { + if (format == mCOLOR_PAL8) { + // Quantization shouldn't be handled here + return NULL; + } + struct mImage* newImage = calloc(1, sizeof(*newImage)); + newImage->width = image->width; + newImage->height = image->height; + newImage->format = format; + if (format == image->format) { + newImage->depth = image->depth; + newImage->stride = image->stride; + newImage->data = malloc(image->stride * image->height * image->depth); + memcpy(newImage->data, image->data, image->stride * image->height * image->depth); + return newImage; + } + newImage->depth = mColorFormatBytes(format); + newImage->stride = image->width; + newImage->data = malloc(image->width * image->height * newImage->depth); + + // TODO: Implement more specializations, e.g. alpha narrowing/widening, channel swapping + size_t x, y; + for (y = 0; y < newImage->height; ++y) { + uintptr_t src = (uintptr_t) ROW(image, y); + uintptr_t dst = (uintptr_t) ROW(newImage, y); + for (x = 0; x < newImage->width; ++x, src += image->depth, dst += newImage->depth) { + uint32_t color; + GET_PIXEL(color, src, image->depth); + color = mImageColorConvert(color, image, format); + PUT_PIXEL(color, dst, newImage->depth); + } + } + return newImage; +} + +void mImageDestroy(struct mImage* image) { + if (image->palette) { + free(image->palette); + } + free(image->data); + free(image); +} + +bool mImageSave(const struct mImage* image, const char* path, const char* format) { + struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); + if (!vf) { + return false; + } + + char extension[PATH_MAX]; + if (!format) { + separatePath(path, NULL, NULL, extension); + format = extension; + } + bool success = mImageSaveVF(image, vf, format); + vf->close(vf); + return success; +} + +#ifdef USE_PNG +bool mImageSavePNG(const struct mImage* image, struct VFile* vf) { + png_structp png = PNGWriteOpen(vf); + png_infop info = NULL; + bool ok = false; + if (png) { + if (image->format == mCOLOR_PAL8) { + info = PNGWriteHeaderPalette(png, image->width, image->height, image->palette, image->palSize); + if (info) { + ok = PNGWritePixelsPalette(png, image->width, image->height, image->stride, image->data); + } + } else { + info = PNGWriteHeader(png, image->width, image->height, image->format); + if (info) { + ok = PNGWritePixels(png, image->width, image->height, image->stride, image->data, image->format); + } + } + PNGWriteClose(png, info); + } + return ok; +} +#endif + +bool mImageSaveVF(const struct mImage* image, struct VFile* vf, const char* format) { +#ifdef USE_PNG + if (strcasecmp(format, "png") == 0) { + return mImageSavePNG(image, vf); + } +#else + UNUSED(image); + UNUSED(vf); + UNUSED(format); +#endif + return false; +} + +uint32_t mImageGetPixelRaw(const struct mImage* image, unsigned x, unsigned y) { + if (x >= image->width || y >= image->height) { + return 0; + } + const void* pixel = PIXEL(image, x, y); + uint32_t color; + switch (image->depth) { + case 1: + color = *(const uint8_t*) pixel; + break; + case 2: + color = *(const uint16_t*) pixel; + break; + case 4: + color = *(const uint32_t*) pixel; + break; + case 3: +#ifdef __BIG_ENDIAN__ + color = ((const uint8_t*) pixel)[0] << 16; + color |= ((const uint8_t*) pixel)[1] << 8; + color |= ((const uint8_t*) pixel)[2]; +#else + color = ((const uint8_t*) pixel)[0]; + color |= ((const uint8_t*) pixel)[1] << 8; + color |= ((const uint8_t*) pixel)[2] << 16; +#endif + break; + default: + // This should never be reached + abort(); + } + return color; +} + +uint32_t mImageGetPixel(const struct mImage* image, unsigned x, unsigned y) { + return mImageColorConvert(mImageGetPixelRaw(image, x, y), image, mCOLOR_ARGB8); +} + +void mImageSetPixelRaw(struct mImage* image, unsigned x, unsigned y, uint32_t color) { + if (x >= image->width || y >= image->height) { + return; + } + void* pixel = PIXEL(image, x, y); + switch (image->depth) { + case 1: + *(uint8_t*) pixel = color; + break; + case 2: + *(uint16_t*) pixel = color; + break; + case 4: + *(uint32_t*) pixel = color; + break; + case 3: +#ifdef __BIG_ENDIAN__ + ((uint8_t*) pixel)[0] = color >> 16; + ((uint8_t*) pixel)[1] = color >> 8; + ((uint8_t*) pixel)[2] = color; +#else + ((uint8_t*) pixel)[0] = color; + ((uint8_t*) pixel)[1] = color >> 8; + ((uint8_t*) pixel)[2] = color >> 16; +#endif + break; + } +} + +void mImageSetPixel(struct mImage* image, unsigned x, unsigned y, uint32_t color) { + mImageSetPixelRaw(image, x, y, mColorConvert(color, mCOLOR_ARGB8, image->format)); +} + +void mImageSetPaletteSize(struct mImage* image, unsigned count) { + if (image->format != mCOLOR_PAL8) { + return; + } + if (count > 256) { + count = 256; + } + image->palSize = count; +} + +void mImageSetPaletteEntry(struct mImage* image, unsigned index, uint32_t color) { + if (image->format != mCOLOR_PAL8) { + return; + } + if (index > 256) { + return; + } + image->palette[index] = color; +} + +#define COMPOSITE_BOUNDS_INIT \ + struct mRectangle dstRect = { \ + .x = 0, \ + .y = 0, \ + .width = image->width, \ + .height = image->height \ + }; \ + struct mRectangle srcRect = { \ + .x = x, \ + .y = y, \ + .width = source->width, \ + .height = source->height \ + }; \ + if (!mRectangleIntersection(&srcRect, &dstRect)) { \ + return; \ + } \ + int srcStartX; \ + int srcStartY; \ + int dstStartX; \ + int dstStartY; \ + if (x < 0) { \ + dstStartX = 0; \ + srcStartX = -x; \ + } else { \ + srcStartX = 0; \ + dstStartX = srcRect.x; \ + } \ + if (y < 0) { \ + dstStartY = 0; \ + srcStartY = -y; \ + } else { \ + srcStartY = 0; \ + dstStartY = srcRect.y; \ + } + +void mImageBlit(struct mImage* image, const struct mImage* source, int x, int y) { + if (image->format == mCOLOR_PAL8) { + // Can't blit to paletted image + return; + } + + COMPOSITE_BOUNDS_INIT; + + for (y = 0; y < srcRect.height; ++y) { + uintptr_t srcPixel = (uintptr_t) PIXEL(source, srcStartX, srcStartY + y); + uintptr_t dstPixel = (uintptr_t) PIXEL(image, dstStartX, dstStartY + y); + for (x = 0; x < srcRect.width; ++x, srcPixel += source->depth, dstPixel += image->depth) { + uint32_t color; + GET_PIXEL(color, srcPixel, source->depth); + color = mImageColorConvert(color, source, image->format); + PUT_PIXEL(color, dstPixel, image->depth); + } + } +} + +void mImageComposite(struct mImage* image, const struct mImage* source, int x, int y) { + if (!mColorFormatHasAlpha(source->format)) { + mImageBlit(image, source, x, y); + return; + } + + if (image->format == mCOLOR_PAL8) { + // Can't blit to paletted image + return; + } + + COMPOSITE_BOUNDS_INIT; + + for (y = 0; y < srcRect.height; ++y) { + uintptr_t srcPixel = (uintptr_t) PIXEL(source, srcStartX, srcStartY + y); + uintptr_t dstPixel = (uintptr_t) PIXEL(image, dstStartX, dstStartY + y); + for (x = 0; x < srcRect.width; ++x, srcPixel += source->depth, dstPixel += image->depth) { + uint32_t color, colorB; + GET_PIXEL(color, srcPixel, source->depth); + color = mImageColorConvert(color, source, mCOLOR_ARGB8); + if (color < 0xFF000000) { + GET_PIXEL(colorB, dstPixel, image->depth); + colorB = mColorConvert(colorB, image->format, mCOLOR_ARGB8); + color = mColorMixARGB8(color, colorB); + } + color = mColorConvert(color, mCOLOR_ARGB8, image->format); + PUT_PIXEL(color, dstPixel, image->depth); + } + } +} + +void mImageCompositeWithAlpha(struct mImage* image, const struct mImage* source, int x, int y, float alpha) { + if (alpha >= 1 && alpha < 257.f / 256.f) { + mImageComposite(image, source, x, y); + return; + } + if (image->format == mCOLOR_PAL8) { + // Can't blit to paletted image + return; + } + if (alpha <= 0) { + return; + } + if (alpha > 256) { + // TODO: Add a slow path for alpha > 1, since we need to check saturation only on this path + alpha = 256; + } + + COMPOSITE_BOUNDS_INIT; + + int fixedAlpha = alpha * 0x200; + + for (y = 0; y < srcRect.height; ++y) { + uintptr_t srcPixel = (uintptr_t) PIXEL(source, srcStartX, srcStartY + y); + uintptr_t dstPixel = (uintptr_t) PIXEL(image, dstStartX, dstStartY + y); + for (x = 0; x < srcRect.width; ++x, srcPixel += source->depth, dstPixel += image->depth) { + uint32_t color, colorB; + GET_PIXEL(color, srcPixel, source->depth); + color = mImageColorConvert(color, source, mCOLOR_ARGB8); + uint32_t alpha = (color >> 24) * fixedAlpha; + alpha >>= 9; + if (alpha > 0xFF) { + alpha = 0xFF; + } + color &= 0x00FFFFFF; + color |= alpha << 24; + + GET_PIXEL(colorB, dstPixel, image->depth); + colorB = mColorConvert(colorB, image->format, mCOLOR_ARGB8); + + color = mColorMixARGB8(color, colorB); + color = mColorConvert(color, mCOLOR_ARGB8, image->format); + PUT_PIXEL(color, dstPixel, image->depth); + } + } +} + +#define FILL_BOUNDS_INIT(X, Y, W, H) \ + struct mRectangle dstRect = { \ + .x = 0, \ + .y = 0, \ + .width = painter->backing->width, \ + .height = painter->backing->height \ + }; \ + struct mRectangle srcRect = { \ + .x = (X), \ + .y = (Y), \ + .width = (W), \ + .height = (H) \ + }; \ + if (!mRectangleIntersection(&srcRect, &dstRect)) { \ + return; \ + } \ + int dstStartX; \ + int dstStartY; \ + if ((X) < 0) { \ + dstStartX = 0; \ + } else { \ + dstStartX = srcRect.x; \ + } \ + if ((Y) < 0) { \ + dstStartY = 0; \ + } else { \ + dstStartY = srcRect.y; \ + } + +void mPainterInit(struct mPainter* painter, struct mImage* backing) { + memset(painter, 0, sizeof(*painter)); + painter->backing = backing; +} + +static void mPainterDrawPixel(struct mPainter* painter, unsigned x, unsigned y, uint32_t color) { + if (painter->blend) { + color = mColorMixARGB8(painter->strokeColor, mImageGetPixel(painter->backing, x, y)); + } + mImageSetPixel(painter->backing, x, y, color); +} + +static void mPainterFillRectangle(struct mPainter* painter, int x, int y, int width, int height) { + FILL_BOUNDS_INIT(x, y, width, height); + + if (!painter->blend || painter->fillColor >= 0xFF000000) { + uint32_t color = mColorConvert(painter->fillColor, mCOLOR_ARGB8, painter->backing->format); + for (y = 0; y < srcRect.height; ++y) { + uintptr_t dstPixel = (uintptr_t) PIXEL(painter->backing, dstStartX, dstStartY + y); + for (x = 0; x < srcRect.width; ++x, dstPixel += painter->backing->depth) { + PUT_PIXEL(color, dstPixel, painter->backing->depth); + } + } + } else { + for (y = 0; y < srcRect.height; ++y) { + uintptr_t dstPixel = (uintptr_t) PIXEL(painter->backing, dstStartX, dstStartY + y); + for (x = 0; x < srcRect.width; ++x, dstPixel += painter->backing->depth) { + uint32_t color; + GET_PIXEL(color, dstPixel, painter->backing->depth); + color = mColorConvert(color, painter->backing->format, mCOLOR_ARGB8); + color = mColorMixARGB8(painter->fillColor, color); + color = mColorConvert(color, mCOLOR_ARGB8, painter->backing->format); + PUT_PIXEL(color, dstPixel, painter->backing->depth); + } + } + } +} + +static void mPainterStrokeRectangle(struct mPainter* painter, int x, int y, int width, int height) { + uint32_t fillColor = painter->fillColor; + painter->fillColor = painter->strokeColor; + if (width < 0 || height < 0) { + return; + } + if ((unsigned) width <= painter->strokeWidth * 2 || (unsigned) height <= painter->strokeWidth * 2) { + mPainterFillRectangle(painter, x, y, width, height); + } else { + int lr = height - painter->strokeWidth; + int tb = width - painter->strokeWidth; + // Top, top-left corner + mPainterFillRectangle(painter, x, y, tb, painter->strokeWidth); + // Left, bottom-left corner + mPainterFillRectangle(painter, x, y + painter->strokeWidth, painter->strokeWidth, lr); + // Bottom, bottom-right corner + mPainterFillRectangle(painter, x + painter->strokeWidth, y + height - painter->strokeWidth, tb, painter->strokeWidth); + // Right, top-right corner + mPainterFillRectangle(painter, x + width - painter->strokeWidth, y, painter->strokeWidth, lr); + } + painter->fillColor = fillColor; +} + +void mPainterDrawRectangle(struct mPainter* painter, int x, int y, int width, int height) { + int interiorW = width - painter->strokeWidth * 2; + int interiorH = height - painter->strokeWidth * 2; + if (painter->fill && interiorW > 0 && interiorH > 0) { + mPainterFillRectangle(painter, x + painter->strokeWidth, y + painter->strokeWidth, interiorW, interiorH); + } + if (painter->strokeWidth) { + mPainterStrokeRectangle(painter, x, y, width, height); + } +} + +void mPainterDrawLine(struct mPainter* painter, int x1, int y1, int x2, int y2) { + if (!painter->strokeWidth) { + return; + } + int dx = x2 - x1; + int dy = y2 - y1; + int x, y; + int xi = 1; + int yi = 1; + int residual; + + int mx = dx; + int my = dy; + if (mx < 0) { + mx = -mx; + } + if (my < 0) { + my = -my; + } + + if (dx < 0) { + xi = -1; + dx = -dx; + } + if (dy < 0) { + yi = -1; + dy = -dy; + } + + unsigned i; + uint32_t color = painter->strokeColor; + + if (mx > my) { + residual = 2 * dy - dx; + y = y1; + for (x = x1; x != x2 + xi; x += xi) { + for (i = 0; i < painter->strokeWidth; ++i) { + mPainterDrawPixel(painter, x, y - painter->strokeWidth / 2 + i, color); + } + if (residual > 0) { + y += yi; + residual -= 2 * dx; + } + residual += 2 * dy; + } + } else { + residual = 2 * dx - dy; + x = x1; + for (y = y1; y != y2 + yi; y += yi) { + for (i = 0; i < painter->strokeWidth; ++i) { + mPainterDrawPixel(painter, x - painter->strokeWidth / 2 + i, y, color); + } + if (residual > 0) { + x += xi; + residual -= 2 * dy; + } + residual += 2 * dx; + } + } + + // TODO: Draw endcaps for widths >2 +} + +static void _drawCircleOctants(struct mPainter* painter, int x, int y, int offx, int offy, int offset, uint32_t color) { + mPainterDrawPixel(painter, x + offy - offset, y + offx - offset, color); + mPainterDrawPixel(painter, x - offy, y + offx - offset, color); + mPainterDrawPixel(painter, x + offy - offset, y - offx, color); + mPainterDrawPixel(painter, x - offy, y - offx, color); + if (offx < offy) { + mPainterDrawPixel(painter, x + offx - offset, y + offy - offset, color); + mPainterDrawPixel(painter, x - offx, y + offy - offset, color); + mPainterDrawPixel(painter, x + offx - offset, y - offy, color); + mPainterDrawPixel(painter, x - offx, y - offy, color); + } +} + +static void _drawCircle2x2(struct mPainter* painter, int x, int y, uint32_t color) { + mPainterDrawPixel(painter, x, y, color); + mPainterDrawPixel(painter, x - 1, y, color); + mPainterDrawPixel(painter, x, y - 1, color); + mPainterDrawPixel(painter, x - 1, y - 1, color); +} + +void mPainterDrawCircle(struct mPainter* painter, int x, int y, int diameter) { + if (diameter < 1) { + return; + } + int radius = diameter / 2; + int offset = (diameter ^ 1) & 1; + int stroke = painter->strokeWidth; + int dx = 1; + int residual0 = 1 - radius; + int dy0 = -2 * radius; + int offx = 0; + int offy; + int y0 = radius; + if (stroke > radius) { + // Clamp stroke + stroke = radius; + if (!offset) { + // Draw center dot as stroke + mPainterDrawPixel(painter, x + radius, y + radius, painter->strokeColor); + } + } else if (!offset && painter->fill) { + // Draw center dot as fill + mPainterDrawPixel(painter, x + radius, y + radius, painter->fillColor); + } + + int residual1 = 1 - radius + stroke; + int dy1 = -2 * (radius - stroke); + int y1 = radius - stroke; + int i; + + if (!offset) { + // Draw central axes + for (i = 0; i < stroke; ++i) { + mPainterDrawPixel(painter, x + radius, y + radius * 2 - i, painter->strokeColor); + mPainterDrawPixel(painter, x + radius, y + i, painter->strokeColor); + mPainterDrawPixel(painter, x + radius * 2 - i, y + radius, painter->strokeColor); + mPainterDrawPixel(painter, x + i, y + radius, painter->strokeColor); + } + if (painter->fill) { + for (i = 1; i < y1 + 1; ++i) { + mPainterDrawPixel(painter, x + radius, y + radius - i, painter->fillColor); + mPainterDrawPixel(painter, x + radius, y + radius + i, painter->fillColor); + mPainterDrawPixel(painter, x + radius - i, y + radius, painter->fillColor); + mPainterDrawPixel(painter, x + radius + i, y + radius, painter->fillColor); + } + } + } + + while (offx < y0) { + if (residual0 >= 0) { + y0 -= 1; + dy0 += 2; + residual0 += dy0; + } + if (residual1 >= 0) { + y1 -= 1; + dy1 += 2; + residual1 += dy1; + } + offx += 1; + dx += 2; + residual0 += dx; + residual1 += dx; + if (stroke) { + // Fill + if (painter->fill) { + if (offx == 1 && y1 == 0 && offset) { + // Special case for diameter-2 fill + _drawCircle2x2(painter, x + radius, y + radius, painter->fillColor); + } else { + for (offy = 0; offy < y1 + 1; ++offy) { + if (offx > offy) { + continue; + } + _drawCircleOctants(painter, x + radius, y + radius, offx, offy, offset, painter->fillColor); + } + } + } + // Stroke + if (radius == 1 && offset) { + // Special case for diameter-2 stroke + _drawCircle2x2(painter, x + radius, y + radius, painter->strokeColor); + } else { + for (offy = y1 + 1; offy < y0 + 1; ++offy) { + if (offx == 1 && offy == 1 && y1 == 0 && offset) { + // Special case for diameter-2 inner fill + continue; + } + if (offx > offy) { + continue; + } + _drawCircleOctants(painter, x + radius, y + radius, offx, offy, offset, painter->strokeColor); + } + } + } else if (painter->fill) { + if (offx == 1 && y0 == 0 && offset) { + // Special case for diameter-2 fill + _drawCircle2x2(painter, x, y, painter->fillColor); + } else { + for (offy = 0; offy < y0 + 1; ++offy) { + if (offx > offy) { + continue; + } + _drawCircleOctants(painter, x + radius, y + radius, offx, offy, offset, painter->fillColor); + } + } + } + } +} + +uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to) { + if (from == to) { + return color; + } + + int r; + int g; + int b; + int a = 0xFF; + + switch (from) { + case mCOLOR_ARGB8: + a = color >> 24; + // Fall through + case mCOLOR_XRGB8: + case mCOLOR_RGB8: + r = (color >> 16) & 0xFF; + g = (color >> 8) & 0xFF; + b = color & 0xFF; + break; + + case mCOLOR_ABGR8: + a = color >> 24; + // Fall through + case mCOLOR_XBGR8: + case mCOLOR_BGR8: + b = (color >> 16) & 0xFF; + g = (color >> 8) & 0xFF; + r = color & 0xFF; + break; + + case mCOLOR_RGBA8: + a = color & 0xFF; + // Fall through + case mCOLOR_RGBX8: + r = (color >> 24) & 0xFF; + g = (color >> 16) & 0xFF; + b = (color >> 8) & 0xFF; + break; + + case mCOLOR_BGRA8: + a = color & 0xFF; + // Fall through + case mCOLOR_BGRX8: + b = (color >> 24) & 0xFF; + g = (color >> 16) & 0xFF; + r = (color >> 8) & 0xFF; + break; + + case mCOLOR_ARGB5: + a = (color >> 15) * 0xFF; + // Fall through + case mCOLOR_RGB5: + r = (((color >> 10) & 0x1F) * 0x21) >> 2; + g = (((color >> 5) & 0x1F) * 0x21) >> 2; + b = ((color & 0x1F) * 0x21) >> 2; + break; + + case mCOLOR_ABGR5: + a = (color >> 15) * 0xFF; + // Fall through + case mCOLOR_BGR5: + b = (((color >> 10) & 0x1F) * 0x21) >> 2; + g = (((color >> 5) & 0x1F) * 0x21) >> 2; + r = ((color & 0x1F) * 0x21) >> 2; + break; + + case mCOLOR_RGBA5: + a = (color & 1) * 0xFF; + r = (((color >> 11) & 0x1F) * 0x21) >> 2; + g = (((color >> 6) & 0x1F) * 0x21) >> 2; + b = (((color >> 1) & 0x1F) * 0x21) >> 2; + break; + case mCOLOR_BGRA5: + a = (color & 1) * 0xFF; + b = (((color >> 11) & 0x1F) * 0x21) >> 2; + g = (((color >> 6) & 0x1F) * 0x21) >> 2; + r = (((color >> 1) & 0x1F) * 0x21) >> 2; + break; + + case mCOLOR_RGB565: + r = (((color >> 11) & 0x1F) * 0x21) >> 2; + g = (((color >> 5) & 0x3F) * 0x41) >> 4; + b = ((color & 0x1F) * 0x21) >> 2; + break; + case mCOLOR_BGR565: + b = (((color >> 11) & 0x1F) * 0x21) >> 2; + g = (((color >> 5) & 0x3F) * 0x41) >> 4; + r = ((color & 0x1F) * 0x21) >> 2; + break; + + case mCOLOR_L8: + r = color; + g = color; + b = color; + break; + + case mCOLOR_PAL8: + case mCOLOR_ANY: + return 0; + } + + color = 0; + switch (to) { + case mCOLOR_XRGB8: + a = 0xFF; + // Fall through + case mCOLOR_ARGB8: + color |= a << 24; + // Fall through + case mCOLOR_RGB8: + color |= r << 16; + color |= g << 8; + color |= b; + break; + case mCOLOR_XBGR8: + a = 0xFF; + // Fall through + case mCOLOR_ABGR8: + color |= a << 24; + // Fall through + case mCOLOR_BGR8: + color |= b << 16; + color |= g << 8; + color |= r; + break; + case mCOLOR_RGBX8: + a = 0xFF; + // Fall through + case mCOLOR_RGBA8: + color |= a; + color |= r << 24; + color |= g << 16; + color |= b << 8; + break; + case mCOLOR_BGRX8: + a = 0xFF; + // Fall through + case mCOLOR_BGRA8: + color |= a; + color |= b << 24; + color |= g << 16; + color |= r << 8; + break; + case mCOLOR_ARGB5: + color |= (!!a << 15); + // Fall through + case mCOLOR_RGB5: + color |= (r >> 3) << 10; + color |= (g >> 3) << 5; + color |= b >> 3; + break; + case mCOLOR_ABGR5: + color |= (!!a << 15); + // Fall through + case mCOLOR_BGR5: + color |= (b >> 3) << 10; + color |= (g >> 3) << 5; + color |= r >> 3; + break; + case mCOLOR_RGBA5: + color |= !!a; + color |= (r >> 3) << 11; + color |= (g >> 3) << 6; + color |= (b >> 3) << 1; + break; + case mCOLOR_BGRA5: + color |= !!a; + color |= (b >> 3) << 11; + color |= (g >> 3) << 6; + color |= (r >> 3) << 1; + break; + case mCOLOR_RGB565: + color |= (r >> 3) << 11; + color |= (g >> 2) << 5; + color |= b >> 3; + break; + case mCOLOR_BGR565: + color |= (b >> 3) << 11; + color |= (g >> 2) << 5; + color |= r >> 3; + break; + case mCOLOR_L8: + // sRGB primaries in fixed point, roughly fudged to saturate to 0xFFFF + color = (55 * r + 184 * g + 18 * b) >> 8; + break; + case mCOLOR_PAL8: + case mCOLOR_ANY: + return 0; + } + + return color; +} + +uint32_t mImageColorConvert(uint32_t color, const struct mImage* from, enum mColorFormat to) { + if (from->format != mCOLOR_PAL8) { + return mColorConvert(color, from->format, to); + } + if (color < from->palSize) { + color = from->palette[color]; + } + return mColorConvert(color, mCOLOR_ARGB8, to); +} diff --git a/src/util/export.c b/src/util/image/export.c similarity index 86% rename from src/util/export.c rename to src/util/image/export.c index cb138ce5a..2b4aad767 100644 --- a/src/util/export.c +++ b/src/util/image/export.c @@ -1,14 +1,14 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2023 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 +#include #include #include -bool exportPaletteRIFF(struct VFile* vf, size_t entries, const uint16_t* colors) { +bool mPaletteExportRIFF(struct VFile* vf, size_t entries, const uint16_t* colors) { if (entries > 0xFFFF) { return false; } @@ -56,7 +56,7 @@ bool exportPaletteRIFF(struct VFile* vf, size_t entries, const uint16_t* colors) return true; } -bool exportPaletteACT(struct VFile* vf, size_t entries, const uint16_t* colors) { +bool mPaletteExportACT(struct VFile* vf, size_t entries, const uint16_t* colors) { if (entries > 256) { return false; } diff --git a/src/util/image/png-io.c b/src/util/image/png-io.c new file mode 100644 index 000000000..e7df1d64f --- /dev/null +++ b/src/util/image/png-io.c @@ -0,0 +1,727 @@ +/* Copyright (c) 2013-2014 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 + +#ifdef USE_PNG + +#include + +static bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries); + +static void _pngWrite(png_structp png, png_bytep buffer, png_size_t size) { + struct VFile* vf = png_get_io_ptr(png); + size_t written = vf->write(vf, buffer, size); + if (written != size) { + png_error(png, "Could not write PNG"); + } +} + +static void _pngRead(png_structp png, png_bytep buffer, png_size_t size) { + struct VFile* vf = png_get_io_ptr(png); + size_t read = vf->read(vf, buffer, size); + if (read != size) { + png_error(png, "Could not read PNG"); + } +} + +png_structp PNGWriteOpen(struct VFile* source) { + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + return 0; + } + if (setjmp(png_jmpbuf(png))) { + png_destroy_write_struct(&png, 0); + return 0; + } + png_set_write_fn(png, source, _pngWrite, 0); + return png; +} + +static png_infop _pngWriteHeader(png_structp png, unsigned width, unsigned height, const uint32_t* palette, unsigned entries, int type) { + png_infop info = png_create_info_struct(png); + if (!info) { + return NULL; + } + if (setjmp(png_jmpbuf(png))) { + return NULL; + } + png_set_IHDR(png, info, width, height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + if (type == PNG_COLOR_TYPE_PALETTE) { + if (!palette) { + return NULL; + } + if (!PNGWritePalette(png, info, palette, entries)) { + return NULL; + } + } + png_write_info(png, info); + return info; +} + +png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height, enum mColorFormat fmt) { + int type; + switch (fmt) { + case mCOLOR_XBGR8: + case mCOLOR_XRGB8: + case mCOLOR_BGRX8: + case mCOLOR_RGBX8: + case mCOLOR_RGB5: + case mCOLOR_BGR5: + case mCOLOR_RGB565: + case mCOLOR_BGR565: + case mCOLOR_RGB8: + case mCOLOR_BGR8: + type = PNG_COLOR_TYPE_RGB; + break; + case mCOLOR_ABGR8: + case mCOLOR_ARGB8: + case mCOLOR_BGRA8: + case mCOLOR_RGBA8: + case mCOLOR_ARGB5: + case mCOLOR_ABGR5: + case mCOLOR_RGBA5: + case mCOLOR_BGRA5: + case mCOLOR_ANY: + type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case mCOLOR_L8: + type = PNG_COLOR_TYPE_GRAY; + break; + case mCOLOR_PAL8: + type = PNG_COLOR_TYPE_PALETTE; + break; + } + return _pngWriteHeader(png, width, height, NULL, 0, type); +} + +png_infop PNGWriteHeaderPalette(png_structp png, unsigned width, unsigned height, const uint32_t* palette, unsigned entries) { + return _pngWriteHeader(png, width, height, palette, entries, PNG_COLOR_TYPE_PALETTE); +} + +static bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries) { + if (!palette || !entries) { + return false; + } + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_color colors[256]; + png_byte trans[256]; + unsigned i; + for (i = 0; i < entries && i < 256; ++i) { + colors[i].red = palette[i] >> 16; + colors[i].green = palette[i] >> 8; + colors[i].blue = palette[i]; + trans[i] = palette[i] >> 24; + } + png_set_PLTE(png, info, colors, entries); + png_set_tRNS(png, info, trans, entries, NULL); + return true; +} + +static void _convertRowXBGR8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 3] = pixelData[x * 4 + 3]; + row[x * 3 + 1] = pixelData[x * 4 + 2]; + row[x * 3 + 2] = pixelData[x * 4 + 1]; +#else + row[x * 3] = pixelData[x * 4]; + row[x * 3 + 1] = pixelData[x * 4 + 1]; + row[x * 3 + 2] = pixelData[x * 4 + 2]; +#endif + } +} + +static void _convertRowXRGB8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 3] = pixelData[x * 4 + 1]; + row[x * 3 + 1] = pixelData[x * 4 + 2]; + row[x * 3 + 2] = pixelData[x * 4 + 3]; +#else + row[x * 3] = pixelData[x * 4 + 2]; + row[x * 3 + 1] = pixelData[x * 4 + 1]; + row[x * 3 + 2] = pixelData[x * 4]; +#endif + } +} + +static void _convertRowBGRX8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 3] = pixelData[x * 4 + 2]; + row[x * 3 + 1] = pixelData[x * 4 + 1]; + row[x * 3 + 2] = pixelData[x * 4]; +#else + row[x * 3] = pixelData[x * 4 + 1]; + row[x * 3 + 1] = pixelData[x * 4 + 2]; + row[x * 3 + 2] = pixelData[x * 4 + 3]; +#endif + } +} + +static void _convertRowRGBX8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 3] = pixelData[x * 4]; + row[x * 3 + 1] = pixelData[x * 4 + 1]; + row[x * 3 + 2] = pixelData[x * 4 + 2]; +#else + row[x * 3] = pixelData[x * 4 + 3]; + row[x * 3 + 1] = pixelData[x * 4 + 2]; + row[x * 3 + 2] = pixelData[x * 4 + 1]; +#endif + } +} + +static void _convertRowABGR8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 4] = pixelData[x * 4 + 3]; + row[x * 4 + 1] = pixelData[x * 4 + 2]; + row[x * 4 + 2] = pixelData[x * 4 + 1]; + row[x * 4 + 3] = pixelData[x * 4]; +#else + row[x * 4] = pixelData[x * 4]; + row[x * 4 + 1] = pixelData[x * 4 + 1]; + row[x * 4 + 2] = pixelData[x * 4 + 2]; + row[x * 4 + 3] = pixelData[x * 4 + 3]; +#endif + } +} + +static void _convertRowARGB8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 4] = pixelData[x * 4 + 1]; + row[x * 4 + 1] = pixelData[x * 4 + 2]; + row[x * 4 + 2] = pixelData[x * 4 + 3]; + row[x * 4 + 3] = pixelData[x * 4]; +#else + row[x * 4] = pixelData[x * 4 + 2]; + row[x * 4 + 1] = pixelData[x * 4 + 1]; + row[x * 4 + 2] = pixelData[x * 4]; + row[x * 4 + 3] = pixelData[x * 4 + 3]; +#endif + } +} + +static void _convertRowBGRA8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 4] = pixelData[x * 4 + 2]; + row[x * 4 + 1] = pixelData[x * 4 + 1]; + row[x * 4 + 2] = pixelData[x * 4]; + row[x * 4 + 3] = pixelData[x * 4 + 3]; +#else + row[x * 4] = pixelData[x * 4 + 1]; + row[x * 4 + 1] = pixelData[x * 4 + 2]; + row[x * 4 + 2] = pixelData[x * 4 + 3]; + row[x * 4 + 3] = pixelData[x * 4]; +#endif + } +} + +static void _convertRowRGBA8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 4] = pixelData[x * 4]; + row[x * 4 + 1] = pixelData[x * 4 + 1]; + row[x * 4 + 2] = pixelData[x * 4 + 2]; + row[x * 4 + 3] = pixelData[x * 4 + 3]; +#else + row[x * 4] = pixelData[x * 4 + 3]; + row[x * 4 + 1] = pixelData[x * 4 + 2]; + row[x * 4 + 2] = pixelData[x * 4 + 1]; + row[x * 4 + 3] = pixelData[x * 4]; +#endif + } +} + +static void _convertRowRGB5(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 3] = (c >> 7) & 0xF8; + row[x * 3 + 1] = (c >> 2) & 0xF8; + row[x * 3 + 2] = (c << 3) & 0xF8; + } +} + +static void _convertRowBGR5(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 3] = (c << 3) & 0xF8; + row[x * 3 + 1] = (c >> 2) & 0xF8; + row[x * 3 + 2] = (c >> 7) & 0xF8; + } +} + +static void _convertRowARGB5(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 4] = (c >> 7) & 0xF8; + row[x * 4 + 1] = (c >> 2) & 0xF8; + row[x * 4 + 2] = (c << 3) & 0xF8; + row[x * 4 + 3] = (c >> 15) * 0xFF; + } +} + +static void _convertRowABGR5(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 4] = (c << 3) & 0xF8; + row[x * 4 + 1] = (c >> 2) & 0xF8; + row[x * 4 + 2] = (c >> 7) & 0xF8; + row[x * 4 + 3] = (c >> 15) * 0xFF; + } +} + +static void _convertRowRGBA5(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 4] = (c >> 8) & 0xF8; + row[x * 4 + 1] = (c >> 3) & 0xF8; + row[x * 4 + 2] = (c << 2) & 0xF8; + row[x * 4 + 3] = (c & 1) * 0xFF; + } +} + +static void _convertRowBGRA5(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 4] = (c << 2) & 0xF8; + row[x * 4 + 1] = (c >> 3) & 0xF8; + row[x * 4 + 2] = (c >> 8) & 0xF8; + row[x * 4 + 3] = (c & 1) * 0xFF; + } +} + +static void _convertRowRGB565(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 3] = (c >> 8) & 0xF8; + row[x * 3 + 1] = (c >> 3) & 0xFC; + row[x * 3 + 2] = (c << 3) & 0xF8; + } +} + +static void _convertRowBGR565(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { + uint16_t c = ((uint16_t*) pixelData)[x]; + row[x * 3] = (c << 3) & 0xF8; + row[x * 3 + 1] = (c >> 3) & 0xFC; + row[x * 3 + 2] = (c >> 8) & 0xF8; + } +} + +static void _convertRowBGR8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 3] = pixelData[x * 3 + 2]; + row[x * 3 + 1] = pixelData[x * 3 + 1]; + row[x * 3 + 2] = pixelData[x * 3]; +#else + row[x * 3] = pixelData[x * 3]; + row[x * 3 + 1] = pixelData[x * 3 + 1]; + row[x * 3 + 2] = pixelData[x * 3 + 2]; +#endif + } +} + +static void _convertRowRGB8(png_bytep row, const png_byte* pixelData, unsigned width) { + unsigned x; + for (x = 0; x < width; ++x) { +#ifdef __BIG_ENDIAN__ + row[x * 3] = pixelData[x * 3]; + row[x * 3 + 1] = pixelData[x * 3 + 1]; + row[x * 3 + 2] = pixelData[x * 3 + 2]; +#else + row[x * 3] = pixelData[x * 3 + 2]; + row[x * 3 + 1] = pixelData[x * 3 + 1]; + row[x * 3 + 2] = pixelData[x * 3]; +#endif + } +} + +bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels, enum mColorFormat fmt) { + int depth; + if (fmt == mCOLOR_L8) { + depth = 1; + } else if (mColorFormatHasAlpha(fmt)) { + depth = 4; + } else { + depth = 3; + } + png_bytep row = malloc(sizeof(png_byte) * width * depth); + if (!row) { + return false; + } + const png_byte* pixelData = pixels; + if (setjmp(png_jmpbuf(png))) { + free(row); + return false; + } + const png_byte* pixelRow = pixelData; + stride *= mColorFormatBytes(fmt); + unsigned i; + for (i = 0; i < height; ++i, pixelRow += stride) { + switch (fmt) { + case mCOLOR_XBGR8: + _convertRowXBGR8(row, pixelRow, width); + break; + case mCOLOR_XRGB8: + _convertRowXRGB8(row, pixelRow, width); + break; + case mCOLOR_BGRX8: + _convertRowBGRX8(row, pixelRow, width); + break; + case mCOLOR_RGBX8: + _convertRowRGBX8(row, pixelRow, width); + break; + case mCOLOR_ABGR8: + _convertRowABGR8(row, pixelRow, width); + break; + case mCOLOR_ARGB8: + _convertRowARGB8(row, pixelRow, width); + break; + case mCOLOR_BGRA8: + _convertRowBGRA8(row, pixelRow, width); + break; + case mCOLOR_RGBA8: + _convertRowRGBA8(row, pixelRow, width); + break; + case mCOLOR_RGB5: + _convertRowRGB5(row, pixelRow, width); + break; + case mCOLOR_BGR5: + _convertRowBGR5(row, pixelRow, width); + break; + case mCOLOR_ARGB5: + _convertRowARGB5(row, pixelRow, width); + break; + case mCOLOR_ABGR5: + _convertRowABGR5(row, pixelRow, width); + break; + case mCOLOR_RGBA5: + _convertRowRGBA5(row, pixelRow, width); + break; + case mCOLOR_BGRA5: + _convertRowBGRA5(row, pixelRow, width); + break; + case mCOLOR_RGB565: + _convertRowRGB565(row, pixelRow, width); + break; + case mCOLOR_BGR565: + _convertRowBGR565(row, pixelRow, width); + break; + case mCOLOR_BGR8: + _convertRowBGR8(row, pixelRow, width); + break; + case mCOLOR_RGB8: + _convertRowRGB8(row, pixelRow, width); + break; + case mCOLOR_L8: + case mCOLOR_PAL8: + memcpy(row, pixelRow, width); + break; + case mCOLOR_ANY: + // Invalid value + longjmp(png_jmpbuf(png), 1); + } + png_write_row(png, row); + } + free(row); + return true; +} + +bool PNGWritePixelsPalette(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { + UNUSED(width); + const png_byte* pixelData = pixels; + if (setjmp(png_jmpbuf(png))) { + return false; + } + unsigned i; + for (i = 0; i < height; ++i) { + png_write_row(png, &pixelData[stride * i]); + } + return true; +} + +bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data) { + char realName[5]; + strncpy(realName, name, 4); + realName[0] = tolower((int) realName[0]); + realName[1] = tolower((int) realName[1]); + realName[4] = '\0'; + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_write_chunk(png, (png_bytep) realName, data, size); + return true; +} + +void PNGWriteClose(png_structp png, png_infop info) { + if (!setjmp(png_jmpbuf(png))) { + png_write_end(png, info); + } + png_destroy_write_struct(&png, &info); +} + +bool isPNG(struct VFile* source) { + png_byte header[PNG_HEADER_BYTES]; + source->seek(source, 0, SEEK_SET); + if (source->read(source, header, PNG_HEADER_BYTES) < PNG_HEADER_BYTES) { + return false; + } + return !png_sig_cmp(header, 0, PNG_HEADER_BYTES); +} + +png_structp PNGReadOpen(struct VFile* source, unsigned offset) { + png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (!png) { + return 0; + } + if (setjmp(png_jmpbuf(png))) { + png_destroy_read_struct(&png, 0, 0); + return 0; + } + png_set_read_fn(png, source, _pngRead); + png_set_sig_bytes(png, offset); + return png; +} + +bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName) { + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_set_read_user_chunk_fn(png, context, handler); + int len = strlen(chunkName); + int chunks = 0; + char* chunkList = strdup(chunkName); + int i; + for (i = 4; i <= len; i += 5) { + chunkList[i] = '\0'; + ++chunks; + } + png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_bytep) chunkList, chunks); + free(chunkList); + return true; +} + +bool PNGReadHeader(png_structp png, png_infop info) { + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_read_info(png, info); + return true; +} + +bool PNGIgnorePixels(png_structp png, png_infop info) { + if (setjmp(png_jmpbuf(png))) { + return false; + } + + unsigned height = png_get_image_height(png, info); + unsigned i; + for (i = 0; i < height; ++i) { + png_read_row(png, 0, 0); + } + return true; +} + +bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { + if (png_get_channels(png, info) != 3) { + return false; + } + + if (setjmp(png_jmpbuf(png))) { + return false; + } + + if (png_get_bit_depth(png, info) == 16) { +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png); +#else + png_set_strip_16(png); +#endif + } + + uint8_t* pixelData = pixels; + unsigned pngHeight = png_get_image_height(png, info); + if (height < pngHeight) { + pngHeight = height; + } + + unsigned pngWidth = png_get_image_width(png, info); + if (width < pngWidth) { + pngWidth = width; + } + + unsigned i; + png_bytep row = malloc(png_get_rowbytes(png, info)); + for (i = 0; i < pngHeight; ++i) { + png_read_row(png, row, 0); + unsigned x; + for (x = 0; x < pngWidth; ++x) { +#ifdef COLOR_16_BIT + uint16_t c = row[x * 3 + 2] >> 3; +#ifdef COLOR_5_6_5 + c |= (row[x * 3 + 1] << 3) & 0x7E0; + c |= (row[x * 3] << 8) & 0xF800; +#else + c |= (row[x * 3 + 1] << 2) & 0x3E0; + c |= (row[x * 3] << 7) & 0x7C00; +#endif + ((uint16_t*) pixelData)[stride * i + x] = c; +#else +#if __BIG_ENDIAN__ + pixelData[stride * i * 4 + x * 4 + 3] = row[x * 3]; + pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 1]; + pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 2]; + pixelData[stride * i * 4 + x * 4] = 0xFF; +#else + pixelData[stride * i * 4 + x * 4] = row[x * 3]; + pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 1]; + pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 2]; + pixelData[stride * i * 4 + x * 4 + 3] = 0xFF; +#endif +#endif + } + } + free(row); + return true; +} + +bool PNGReadPixelsA(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { + if (png_get_channels(png, info) != 4) { + return false; + } + + if (setjmp(png_jmpbuf(png))) { + return false; + } + + if (png_get_bit_depth(png, info) == 16) { +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png); +#else + png_set_strip_16(png); +#endif + } + + uint8_t* pixelData = pixels; + unsigned pngHeight = png_get_image_height(png, info); + if (height < pngHeight) { + pngHeight = height; + } + + unsigned pngWidth = png_get_image_width(png, info); + if (width < pngWidth) { + pngWidth = width; + } + + unsigned i; + png_bytep row = malloc(png_get_rowbytes(png, info)); + for (i = 0; i < pngHeight; ++i) { + png_read_row(png, row, 0); + unsigned x; + for (x = 0; x < pngWidth; ++x) { +#ifdef COLOR_16_BIT + uint16_t c = row[x * 4 + 2] >> 3; +#ifdef COLOR_5_6_5 + c |= (row[x * 4 + 1] << 3) & 0x7E0; + c |= (row[x * 4] << 8) & 0xF800; +#else + c |= (row[x * 4 + 1] << 2) & 0x3E0; + c |= (row[x * 4] << 7) & 0x7C00; +#endif + ((uint16_t*) pixelData)[stride * i + x] = c; +#else +#if __BIG_ENDIAN__ + pixelData[stride * i * 4 + x * 4 + 3] = row[x * 4]; + pixelData[stride * i * 4 + x * 4 + 2] = row[x * 4 + 1]; + pixelData[stride * i * 4 + x * 4 + 1] = row[x * 4 + 2]; + pixelData[stride * i * 4 + x * 4] = row[x * 4 + 3]; +#else + pixelData[stride * i * 4 + x * 4] = row[x * 4]; + pixelData[stride * i * 4 + x * 4 + 1] = row[x * 4 + 1]; + pixelData[stride * i * 4 + x * 4 + 2] = row[x * 4 + 2]; + pixelData[stride * i * 4 + x * 4 + 3] = row[x * 4 + 3]; +#endif +#endif + } + } + free(row); + return true; +} + +bool PNGReadPixels8(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { + if (png_get_channels(png, info) != 1) { + return false; + } + + if (setjmp(png_jmpbuf(png))) { + return false; + } + + if (png_get_bit_depth(png, info) == 16) { +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + png_set_scale_16(png); +#else + png_set_strip_16(png); +#endif + } + + uint8_t* pixelData = pixels; + unsigned pngHeight = png_get_image_height(png, info); + if (height < pngHeight) { + pngHeight = height; + } + + unsigned pngWidth = png_get_image_width(png, info); + if (width < pngWidth) { + pngWidth = width; + } + + unsigned i; + for (i = 0; i < pngHeight; ++i) { + png_read_row(png, &pixelData[stride * i], 0); + } + return true; +} + + +bool PNGReadFooter(png_structp png, png_infop end) { + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_read_end(png, end); + return true; +} + +void PNGReadClose(png_structp png, png_infop info, png_infop end) { + png_destroy_read_struct(&png, &info, &end); +} + +#endif diff --git a/src/util/png-io.c b/src/util/png-io.c deleted file mode 100644 index 6c25f399c..000000000 --- a/src/util/png-io.c +++ /dev/null @@ -1,423 +0,0 @@ -/* Copyright (c) 2013-2014 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 - -#ifdef USE_PNG - -#include - -static void _pngWrite(png_structp png, png_bytep buffer, png_size_t size) { - struct VFile* vf = png_get_io_ptr(png); - size_t written = vf->write(vf, buffer, size); - if (written != size) { - png_error(png, "Could not write PNG"); - } -} - -static void _pngRead(png_structp png, png_bytep buffer, png_size_t size) { - struct VFile* vf = png_get_io_ptr(png); - size_t read = vf->read(vf, buffer, size); - if (read != size) { - png_error(png, "Could not read PNG"); - } -} - -png_structp PNGWriteOpen(struct VFile* source) { - png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!png) { - return 0; - } - if (setjmp(png_jmpbuf(png))) { - png_destroy_write_struct(&png, 0); - return 0; - } - png_set_write_fn(png, source, _pngWrite, 0); - return png; -} - -static png_infop _pngWriteHeader(png_structp png, unsigned width, unsigned height, int type) { - png_infop info = png_create_info_struct(png); - if (!info) { - return 0; - } - if (setjmp(png_jmpbuf(png))) { - return 0; - } - png_set_IHDR(png, info, width, height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_write_info(png, info); - return info; -} - -png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height) { - return _pngWriteHeader(png, width, height, PNG_COLOR_TYPE_RGB); -} - -png_infop PNGWriteHeaderA(png_structp png, unsigned width, unsigned height) { - return _pngWriteHeader(png, width, height, PNG_COLOR_TYPE_RGB_ALPHA); -} - -png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height) { - return _pngWriteHeader(png, width, height, PNG_COLOR_TYPE_PALETTE); -} - -bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries) { - if (!palette || !entries) { - return false; - } - if (setjmp(png_jmpbuf(png))) { - return false; - } - png_color colors[256]; - png_byte trans[256]; - unsigned i; - for (i = 0; i < entries && i < 256; ++i) { - colors[i].red = palette[i]; - colors[i].green = palette[i] >> 8; - colors[i].blue = palette[i] >> 16; - trans[i] = palette[i] >> 24; - } - png_set_PLTE(png, info, colors, entries); - png_set_tRNS(png, info, trans, entries, NULL); - png_write_info(png, info); - return true; -} - -bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { - png_bytep row = malloc(sizeof(png_byte) * width * 3); - if (!row) { - return false; - } - const png_byte* pixelData = pixels; - if (setjmp(png_jmpbuf(png))) { - free(row); - return false; - } - unsigned i; - for (i = 0; i < height; ++i) { - unsigned x; - for (x = 0; x < width; ++x) { -#ifdef COLOR_16_BIT - uint16_t c = ((uint16_t*) pixelData)[stride * i + x]; -#ifdef COLOR_5_6_5 - row[x * 3] = (c >> 8) & 0xF8; - row[x * 3 + 1] = (c >> 3) & 0xFC; - row[x * 3 + 2] = (c << 3) & 0xF8; -#else - row[x * 3] = (c >> 7) & 0xF8; - row[x * 3 + 1] = (c >> 2) & 0xF8; - row[x * 3 + 2] = (c << 3) & 0xF8; -#endif -#else -#ifdef __BIG_ENDIAN__ - row[x * 3] = pixelData[stride * i * 4 + x * 4 + 3]; - row[x * 3 + 1] = pixelData[stride * i * 4 + x * 4 + 2]; - row[x * 3 + 2] = pixelData[stride * i * 4 + x * 4 + 1]; -#else - row[x * 3] = pixelData[stride * i * 4 + x * 4]; - row[x * 3 + 1] = pixelData[stride * i * 4 + x * 4 + 1]; - row[x * 3 + 2] = pixelData[stride * i * 4 + x * 4 + 2]; -#endif -#endif - } - png_write_row(png, row); - } - free(row); - return true; -} - -bool PNGWritePixelsA(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { - png_bytep row = malloc(sizeof(png_byte) * width * 4); - if (!row) { - return false; - } - const png_byte* pixelData = pixels; - if (setjmp(png_jmpbuf(png))) { - free(row); - return false; - } - unsigned i; - for (i = 0; i < height; ++i) { - unsigned x; - for (x = 0; x < width; ++x) { -#ifdef COLOR_16_BIT - uint16_t c = ((uint16_t*) pixelData)[stride * i + x]; -#ifdef COLOR_5_6_5 - row[x * 4] = (c >> 8) & 0xF8; - row[x * 4 + 1] = (c >> 3) & 0xFC; - row[x * 4 + 2] = (c << 3) & 0xF8; - row[x * 4 + 3] = 0xFF; -#else - row[x * 4] = (c >> 7) & 0xF8; - row[x * 4 + 1] = (c >> 2) & 0xF8; - row[x * 4 + 2] = (c << 3) & 0xF8; - row[x * 4 + 3] = (c >> 15) * 0xFF; -#endif -#else -#ifdef __BIG_ENDIAN__ - row[x * 4] = pixelData[stride * i * 4 + x * 4 + 3]; - row[x * 4 + 1] = pixelData[stride * i * 4 + x * 4 + 2]; - row[x * 4 + 2] = pixelData[stride * i * 4 + x * 4 + 1]; - row[x * 4 + 3] = pixelData[stride * i * 4 + x * 4]; -#else - row[x * 4] = pixelData[stride * i * 4 + x * 4]; - row[x * 4 + 1] = pixelData[stride * i * 4 + x * 4 + 1]; - row[x * 4 + 2] = pixelData[stride * i * 4 + x * 4 + 2]; - row[x * 4 + 3] = pixelData[stride * i * 4 + x * 4 + 3]; -#endif -#endif - } - png_write_row(png, row); - } - free(row); - return true; -} - -bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { - UNUSED(width); - const png_byte* pixelData = pixels; - if (setjmp(png_jmpbuf(png))) { - return false; - } - unsigned i; - for (i = 0; i < height; ++i) { - png_write_row(png, &pixelData[stride * i]); - } - return true; -} - -bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data) { - char realName[5]; - strncpy(realName, name, 4); - realName[0] = tolower((int) realName[0]); - realName[1] = tolower((int) realName[1]); - realName[4] = '\0'; - if (setjmp(png_jmpbuf(png))) { - return false; - } - png_write_chunk(png, (png_bytep) realName, data, size); - return true; -} - -void PNGWriteClose(png_structp png, png_infop info) { - if (!setjmp(png_jmpbuf(png))) { - png_write_end(png, info); - } - png_destroy_write_struct(&png, &info); -} - -bool isPNG(struct VFile* source) { - png_byte header[PNG_HEADER_BYTES]; - source->seek(source, 0, SEEK_SET); - if (source->read(source, header, PNG_HEADER_BYTES) < PNG_HEADER_BYTES) { - return false; - } - return !png_sig_cmp(header, 0, PNG_HEADER_BYTES); -} - -png_structp PNGReadOpen(struct VFile* source, unsigned offset) { - png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (!png) { - return 0; - } - if (setjmp(png_jmpbuf(png))) { - png_destroy_read_struct(&png, 0, 0); - return 0; - } - png_set_read_fn(png, source, _pngRead); - png_set_sig_bytes(png, offset); - return png; -} - -bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName) { - if (setjmp(png_jmpbuf(png))) { - return false; - } - png_set_read_user_chunk_fn(png, context, handler); - int len = strlen(chunkName); - int chunks = 0; - char* chunkList = strdup(chunkName); - int i; - for (i = 4; i <= len; i += 5) { - chunkList[i] = '\0'; - ++chunks; - } - png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_bytep) chunkList, chunks); - free(chunkList); - return true; -} - -bool PNGReadHeader(png_structp png, png_infop info) { - if (setjmp(png_jmpbuf(png))) { - return false; - } - png_read_info(png, info); - return true; -} - -bool PNGIgnorePixels(png_structp png, png_infop info) { - if (setjmp(png_jmpbuf(png))) { - return false; - } - - unsigned height = png_get_image_height(png, info); - unsigned i; - for (i = 0; i < height; ++i) { - png_read_row(png, 0, 0); - } - return true; -} - -bool PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { - if (png_get_channels(png, info) != 3) { - return false; - } - - if (setjmp(png_jmpbuf(png))) { - return false; - } - - uint8_t* pixelData = pixels; - unsigned pngHeight = png_get_image_height(png, info); - if (height < pngHeight) { - pngHeight = height; - } - - unsigned pngWidth = png_get_image_width(png, info); - if (width < pngWidth) { - pngWidth = width; - } - - unsigned i; - png_bytep row = malloc(png_get_rowbytes(png, info)); - for (i = 0; i < pngHeight; ++i) { - png_read_row(png, row, 0); - unsigned x; - for (x = 0; x < pngWidth; ++x) { -#ifdef COLOR_16_BIT - uint16_t c = row[x * 3 + 2] >> 3; -#ifdef COLOR_5_6_5 - c |= (row[x * 3 + 1] << 3) & 0x7E0; - c |= (row[x * 3] << 8) & 0xF800; -#else - c |= (row[x * 3 + 1] << 2) & 0x3E0; - c |= (row[x * 3] << 7) & 0x7C00; -#endif - ((uint16_t*) pixelData)[stride * i + x] = c; -#else -#if __BIG_ENDIAN__ - pixelData[stride * i * 4 + x * 4 + 3] = row[x * 3]; - pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 1]; - pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 2]; - pixelData[stride * i * 4 + x * 4] = 0xFF; -#else - pixelData[stride * i * 4 + x * 4] = row[x * 3]; - pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 1]; - pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 2]; - pixelData[stride * i * 4 + x * 4 + 3] = 0xFF; -#endif -#endif - } - } - free(row); - return true; -} - -bool PNGReadPixelsA(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { - if (png_get_channels(png, info) != 4) { - return false; - } - - if (setjmp(png_jmpbuf(png))) { - return false; - } - - uint8_t* pixelData = pixels; - unsigned pngHeight = png_get_image_height(png, info); - if (height < pngHeight) { - pngHeight = height; - } - - unsigned pngWidth = png_get_image_width(png, info); - if (width < pngWidth) { - pngWidth = width; - } - - unsigned i; - png_bytep row = malloc(png_get_rowbytes(png, info)); - for (i = 0; i < pngHeight; ++i) { - png_read_row(png, row, 0); - unsigned x; - for (x = 0; x < pngWidth; ++x) { -#ifdef COLOR_16_BIT - uint16_t c = row[x * 4 + 2] >> 3; -#ifdef COLOR_5_6_5 - c |= (row[x * 4 + 1] << 3) & 0x7E0; - c |= (row[x * 4] << 8) & 0xF800; -#else - c |= (row[x * 4 + 1] << 2) & 0x3E0; - c |= (row[x * 4] << 7) & 0x7C00; -#endif - ((uint16_t*) pixelData)[stride * i + x] = c; -#else -#if __BIG_ENDIAN__ - pixelData[stride * i * 4 + x * 4 + 3] = row[x * 4]; - pixelData[stride * i * 4 + x * 4 + 2] = row[x * 4 + 1]; - pixelData[stride * i * 4 + x * 4 + 1] = row[x * 4 + 2]; - pixelData[stride * i * 4 + x * 4] = row[x * 4 + 3]; -#else - pixelData[stride * i * 4 + x * 4] = row[x * 4]; - pixelData[stride * i * 4 + x * 4 + 1] = row[x * 4 + 1]; - pixelData[stride * i * 4 + x * 4 + 2] = row[x * 4 + 2]; - pixelData[stride * i * 4 + x * 4 + 3] = row[x * 4 + 3]; -#endif -#endif - } - } - free(row); - return true; -} - -bool PNGReadPixels8(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) { - if (png_get_channels(png, info) != 1) { - return false; - } - - if (setjmp(png_jmpbuf(png))) { - return false; - } - - uint8_t* pixelData = pixels; - unsigned pngHeight = png_get_image_height(png, info); - if (height < pngHeight) { - pngHeight = height; - } - - unsigned pngWidth = png_get_image_width(png, info); - if (width < pngWidth) { - pngWidth = width; - } - - unsigned i; - for (i = 0; i < pngHeight; ++i) { - png_read_row(png, &pixelData[stride * i], 0); - } - return true; -} - - -bool PNGReadFooter(png_structp png, png_infop end) { - if (setjmp(png_jmpbuf(png))) { - return false; - } - png_read_end(png, end); - return true; -} - -void PNGReadClose(png_structp png, png_infop info, png_infop end) { - png_destroy_read_struct(&png, &info, &end); -} - -#endif diff --git a/src/util/sfo.c b/src/util/sfo.c index 90142897b..339da1d8e 100644 --- a/src/util/sfo.c +++ b/src/util/sfo.c @@ -161,6 +161,9 @@ bool SfoWrite(struct Table* sfo, struct VFile* vf) { case PSF_TYPE_U32: sortedEntries[i].size = 4; break; + default: + free(sortedEntries); + return false; } } dataSize += ALIGN4(sortedEntries[i].size); diff --git a/src/util/string.c b/src/util/string.c index 9e007dc2d..1a2ffe7a4 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -5,12 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include -#include - #include -DEFINE_VECTOR(StringList, char*); - #ifndef HAVE_STRNDUP char* strndup(const char* start, size_t len) { // This is suboptimal, but anything recent should have strndup diff --git a/src/util/test/color.c b/src/util/test/color.c new file mode 100644 index 000000000..6977795c6 --- /dev/null +++ b/src/util/test/color.c @@ -0,0 +1,173 @@ +/* Copyright (c) 2013-2023 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 + +M_TEST_DEFINE(channelSwap32) { + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ARGB8, mCOLOR_ABGR8), 0xFFCCBBAA); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ABGR8, mCOLOR_ARGB8), 0xFFCCBBAA); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_XRGB8, mCOLOR_XBGR8), 0xFFCCBBAA); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_XBGR8, mCOLOR_XRGB8), 0xFFCCBBAA); + assert_int_equal(mColorConvert(0xAABBCC, mCOLOR_RGB8, mCOLOR_BGR8), 0xCCBBAA); + assert_int_equal(mColorConvert(0xAABBCC, mCOLOR_BGR8, mCOLOR_RGB8), 0xCCBBAA); + + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ARGB8, mCOLOR_RGBA8), 0xAABBCCFF); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ABGR8, mCOLOR_BGRA8), 0xAABBCCFF); + assert_int_equal(mColorConvert(0xAABBCCFF, mCOLOR_RGBA8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xAABBCCFF, mCOLOR_BGRA8, mCOLOR_ABGR8), 0xFFAABBCC); + + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ARGB8, mCOLOR_BGRA8), 0xCCBBAAFF); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ABGR8, mCOLOR_RGBA8), 0xCCBBAAFF); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_RGBA8, mCOLOR_ABGR8), 0xCCBBAAFF); + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_BGRA8, mCOLOR_ARGB8), 0xCCBBAAFF); +} + +M_TEST_DEFINE(channelSwap16) { + assert_int_equal(mColorConvert(0xFFE0, mCOLOR_ARGB5, mCOLOR_ABGR5), 0x83FF); + assert_int_equal(mColorConvert(0xFFE0, mCOLOR_ABGR5, mCOLOR_ARGB5), 0x83FF); + assert_int_equal(mColorConvert(0x7FE0, mCOLOR_RGB5, mCOLOR_BGR5), 0x03FF); + assert_int_equal(mColorConvert(0x7FE0, mCOLOR_BGR5, mCOLOR_RGB5), 0x03FF); + assert_int_equal(mColorConvert(0xFFE0, mCOLOR_RGB565, mCOLOR_BGR565), 0x07FF); + assert_int_equal(mColorConvert(0xFFE0, mCOLOR_BGR565, mCOLOR_RGB565), 0x07FF); + + assert_int_equal(mColorConvert(0xFFE0, mCOLOR_ARGB5, mCOLOR_RGBA5), 0xFFC1); + assert_int_equal(mColorConvert(0xFFE0, mCOLOR_RGBA5, mCOLOR_ARGB5), 0x7FF0); +} + +M_TEST_DEFINE(convertQuantizeOpaque) { + assert_int_equal(mColorConvert(0xA0B0C0, mCOLOR_XRGB8, mCOLOR_RGB5), (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA1B1C1, mCOLOR_XRGB8, mCOLOR_RGB5), (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA2B2C2, mCOLOR_XRGB8, mCOLOR_RGB5), (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA4B4C4, mCOLOR_XRGB8, mCOLOR_RGB5), (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA8B8C8, mCOLOR_XRGB8, mCOLOR_RGB5), (0xA << 11) | (0x1B << 6) | (0x1C << 1) | 1); + + assert_int_equal(mColorConvert(0xA0B0C0, mCOLOR_XRGB8, mCOLOR_BGR5), (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA1B1C1, mCOLOR_XRGB8, mCOLOR_BGR5), (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA2B2C2, mCOLOR_XRGB8, mCOLOR_BGR5), (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA4B4C4, mCOLOR_XRGB8, mCOLOR_BGR5), (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA8B8C8, mCOLOR_XRGB8, mCOLOR_BGR5), (0xC << 11) | (0x1B << 6) | (0x1A << 1) | 1); + + assert_int_equal(mColorConvert(0xA0B0C0, mCOLOR_XRGB8, mCOLOR_RGB565), (0xA << 12) | (0xB << 7) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA1B1C1, mCOLOR_XRGB8, mCOLOR_RGB565), (0xA << 12) | (0xB << 7) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA2B2C2, mCOLOR_XRGB8, mCOLOR_RGB565), (0xA << 12) | (0xB << 7) | (0xC << 1)); + assert_int_equal(mColorConvert(0xA4B4C4, mCOLOR_XRGB8, mCOLOR_RGB565), (0xA << 12) | (0xB << 7) | (0x1C << 1)); + assert_int_equal(mColorConvert(0xA8B8C8, mCOLOR_XRGB8, mCOLOR_RGB565), (0xA << 12) | (0x1B << 7) | (0x2C << 1) | 1); + assert_int_equal(mColorConvert(0xACBCCC, mCOLOR_XRGB8, mCOLOR_RGB565), (0xA << 12) | (0x1B << 7) | (0x3C << 1) | 1); + + assert_int_equal(mColorConvert(0xA0B0C0, mCOLOR_XRGB8, mCOLOR_BGR565), (0xC << 12) | (0xB << 7) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA1B1C1, mCOLOR_XRGB8, mCOLOR_BGR565), (0xC << 12) | (0xB << 7) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA2B2C2, mCOLOR_XRGB8, mCOLOR_BGR565), (0xC << 12) | (0xB << 7) | (0xA << 1)); + assert_int_equal(mColorConvert(0xA4B4C4, mCOLOR_XRGB8, mCOLOR_BGR565), (0xC << 12) | (0xB << 7) | (0x1A << 1)); + assert_int_equal(mColorConvert(0xA8B8C8, mCOLOR_XRGB8, mCOLOR_BGR565), (0xC << 12) | (0x1B << 7) | (0x2A << 1) | 1); + assert_int_equal(mColorConvert(0xACBCCC, mCOLOR_XRGB8, mCOLOR_BGR565), (0xC << 12) | (0x1B << 7) | (0x3A << 1) | 1); +} + +M_TEST_DEFINE(convertQuantizeTransparent) { + assert_int_equal(mColorConvert(0xFFA0B0C0, mCOLOR_ARGB8, mCOLOR_ARGB5), 0x8000 | (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0x00A0B0C0, mCOLOR_ARGB8, mCOLOR_ARGB5), (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0xFEA0B0C0, mCOLOR_ARGB8, mCOLOR_ARGB5), 0x8000 | (0xA << 11) | (0xB << 6) | (0xC << 1)); + assert_int_equal(mColorConvert(0x01A0B0C0, mCOLOR_ARGB8, mCOLOR_ARGB5), 0x8000 | (0xA << 11) | (0xB << 6) | (0xC << 1)); + + assert_int_equal(mColorConvert(0xFFA0B0C0, mCOLOR_ARGB8, mCOLOR_ABGR5), 0x8000 | (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0x00A0B0C0, mCOLOR_ARGB8, mCOLOR_ABGR5), (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0xFEA0B0C0, mCOLOR_ARGB8, mCOLOR_ABGR5), 0x8000 | (0xC << 11) | (0xB << 6) | (0xA << 1)); + assert_int_equal(mColorConvert(0x01A0B0C0, mCOLOR_ARGB8, mCOLOR_ABGR5), 0x8000 | (0xC << 11) | (0xB << 6) | (0xA << 1)); + + assert_int_equal(mColorConvert(0xFFA0B0C0, mCOLOR_ARGB8, mCOLOR_RGBA5), 1 | (0xA << 12) | (0xB << 7) | (0xC << 2)); + assert_int_equal(mColorConvert(0x00A0B0C0, mCOLOR_ARGB8, mCOLOR_RGBA5), (0xA << 12) | (0xB << 7) | (0xC << 2)); + assert_int_equal(mColorConvert(0xFEA0B0C0, mCOLOR_ARGB8, mCOLOR_RGBA5), 1 | (0xA << 12) | (0xB << 7) | (0xC << 2)); + assert_int_equal(mColorConvert(0x01A0B0C0, mCOLOR_ARGB8, mCOLOR_RGBA5), 1 | (0xA << 12) | (0xB << 7) | (0xC << 2)); + + assert_int_equal(mColorConvert(0xFFA0B0C0, mCOLOR_ARGB8, mCOLOR_BGRA5), 1 | (0xC << 12) | (0xB << 7) | (0xA << 2)); + assert_int_equal(mColorConvert(0x00A0B0C0, mCOLOR_ARGB8, mCOLOR_BGRA5), (0xC << 12) | (0xB << 7) | (0xA << 2)); + assert_int_equal(mColorConvert(0xFEA0B0C0, mCOLOR_ARGB8, mCOLOR_BGRA5), 1 | (0xC << 12) | (0xB << 7) | (0xA << 2)); + assert_int_equal(mColorConvert(0x01A0B0C0, mCOLOR_ARGB8, mCOLOR_BGRA5), 1 | (0xC << 12) | (0xB << 7) | (0xA << 2)); +} + +M_TEST_DEFINE(convertToOpaque) { + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ARGB8, mCOLOR_XRGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xFEAABBCC, mCOLOR_ARGB8, mCOLOR_XRGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0x01AABBCC, mCOLOR_ARGB8, mCOLOR_XRGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0x00AABBCC, mCOLOR_ARGB8, mCOLOR_XRGB8), 0xFFAABBCC); + + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_ARGB8, mCOLOR_RGB8), 0xAABBCC); + assert_int_equal(mColorConvert(0xFEAABBCC, mCOLOR_ARGB8, mCOLOR_RGB8), 0xAABBCC); + assert_int_equal(mColorConvert(0x01AABBCC, mCOLOR_ARGB8, mCOLOR_RGB8), 0xAABBCC); + assert_int_equal(mColorConvert(0x00AABBCC, mCOLOR_ARGB8, mCOLOR_RGB8), 0xAABBCC); + + assert_int_equal(mColorConvert(0xAABBCCFF, mCOLOR_RGBA8, mCOLOR_XRGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xAABBCCFE, mCOLOR_RGBA8, mCOLOR_XRGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xAABBCC01, mCOLOR_RGBA8, mCOLOR_XRGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xAABBCC00, mCOLOR_RGBA8, mCOLOR_XRGB8), 0xFFAABBCC); + + assert_int_equal(mColorConvert(0xAABBCCFF, mCOLOR_RGBA8, mCOLOR_RGB8), 0xAABBCC); + assert_int_equal(mColorConvert(0xAABBCCFE, mCOLOR_RGBA8, mCOLOR_RGB8), 0xAABBCC); + assert_int_equal(mColorConvert(0xAABBCC01, mCOLOR_RGBA8, mCOLOR_RGB8), 0xAABBCC); + assert_int_equal(mColorConvert(0xAABBCC00, mCOLOR_RGBA8, mCOLOR_RGB8), 0xAABBCC); + + assert_int_equal(mColorConvert(0x7FFF, mCOLOR_ARGB5, mCOLOR_RGB5), 0x7FFF); + assert_int_equal(mColorConvert(0xFFFF, mCOLOR_ARGB5, mCOLOR_RGB5), 0x7FFF); + + assert_int_equal(mColorConvert(0xFFFE, mCOLOR_RGBA5, mCOLOR_RGB5), 0x7FFF); + assert_int_equal(mColorConvert(0xFFFF, mCOLOR_RGBA5, mCOLOR_RGB5), 0x7FFF); +} + +M_TEST_DEFINE(convertToAlpha) { + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_XRGB8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xFEAABBCC, mCOLOR_XRGB8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0x01AABBCC, mCOLOR_XRGB8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0x00AABBCC, mCOLOR_XRGB8, mCOLOR_ARGB8), 0xFFAABBCC); + + assert_int_equal(mColorConvert(0xFFAABBCC, mCOLOR_RGB8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0xFEAABBCC, mCOLOR_RGB8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0x01AABBCC, mCOLOR_RGB8, mCOLOR_ARGB8), 0xFFAABBCC); + assert_int_equal(mColorConvert(0x00AABBCC, mCOLOR_RGB8, mCOLOR_ARGB8), 0xFFAABBCC); + + assert_int_equal(mColorConvert(0x7FFF, mCOLOR_RGB5, mCOLOR_ARGB5), 0xFFFF); + assert_int_equal(mColorConvert(0xFFFF, mCOLOR_RGB5, mCOLOR_ARGB5), 0xFFFF); + + assert_int_equal(mColorConvert(0x7FFF, mCOLOR_RGB5, mCOLOR_RGBA5), 0xFFFF); + assert_int_equal(mColorConvert(0xFFFF, mCOLOR_RGB5, mCOLOR_RGBA5), 0xFFFF); +} + +M_TEST_DEFINE(convertFromGray) { + int i; + for (i = 0; i < 256; ++i) { + assert_int_equal(mColorConvert(i, mCOLOR_L8, mCOLOR_RGB8), (i << 16) | (i << 8) | i); + assert_int_equal(mColorConvert(i, mCOLOR_L8, mCOLOR_ARGB8), 0xFF000000 | (i << 16) | (i << 8) | i); + } +} + +M_TEST_DEFINE(convertToGray) { + int i; + for (i = 0; i < 256; ++i) { + assert_int_equal(mColorConvert((i << 16) | (i << 8) | i, mCOLOR_RGB8, mCOLOR_L8), i); + assert_int_equal(mColorConvert((i << 16) | (i << 8) | i, mCOLOR_ARGB8, mCOLOR_L8), i); + assert_int_equal(mColorConvert(0xFF000000 | (i << 16) | (i << 8) | i, mCOLOR_ARGB8, mCOLOR_L8), i); + } +} + +M_TEST_DEFINE(alphaBlendARGB8) { + assert_int_equal(mColorMixARGB8(0xFF012345, 0xFF987654), 0xFF012345); + assert_int_equal(mColorMixARGB8(0x00012345, 0xFF987654), 0xFF987654); + assert_int_equal(mColorMixARGB8(0x80012345, 0xFF987654), 0xFF4C4C4C); + assert_int_equal(mColorMixARGB8(0x80012345, 0x40987654), 0x9F1F3347); + assert_int_equal(mColorMixARGB8(0x01012345, 0xFF987654), 0xFF977553); + assert_int_equal(mColorMixARGB8(0x01012345, 0xFD987654), 0xFD977553); +} + +M_TEST_SUITE_DEFINE(Color, + cmocka_unit_test(channelSwap32), + cmocka_unit_test(channelSwap16), + cmocka_unit_test(convertQuantizeOpaque), + cmocka_unit_test(convertQuantizeTransparent), + cmocka_unit_test(convertToOpaque), + cmocka_unit_test(convertToAlpha), + cmocka_unit_test(convertFromGray), + cmocka_unit_test(convertToGray), + cmocka_unit_test(alphaBlendARGB8), +) diff --git a/src/util/test/geometry.c b/src/util/test/geometry.c new file mode 100644 index 000000000..419a1b1da --- /dev/null +++ b/src/util/test/geometry.c @@ -0,0 +1,1454 @@ +/* Copyright (c) 2013-2023 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 + +M_TEST_DEFINE(unionRectOrigin) { + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 1, + .height = 1 + }; + struct mRectangle b = { + .x = 1, + .y = 1, + .width = 1, + .height = 1 + }; + mRectangleUnion(&a, &b); + assert_int_equal(a.x, 0); + assert_int_equal(a.y, 0); + assert_int_equal(a.width, 2); + assert_int_equal(a.height, 2); +} + +M_TEST_DEFINE(unionRectOriginSwapped) { + struct mRectangle a = { + .x = 1, + .y = 1, + .width = 1, + .height = 1 + }; + struct mRectangle b = { + .x = 0, + .y = 0, + .width = 1, + .height = 1 + }; + mRectangleUnion(&a, &b); + assert_int_equal(a.x, 0); + assert_int_equal(a.y, 0); + assert_int_equal(a.width, 2); + assert_int_equal(a.height, 2); +} + +M_TEST_DEFINE(unionRectNonOrigin) { + struct mRectangle a = { + .x = 1, + .y = 1, + .width = 1, + .height = 1 + }; + struct mRectangle b = { + .x = 2, + .y = 2, + .width = 1, + .height = 1 + }; + mRectangleUnion(&a, &b); + assert_int_equal(a.x, 1); + assert_int_equal(a.y, 1); + assert_int_equal(a.width, 2); + assert_int_equal(a.height, 2); +} + +M_TEST_DEFINE(unionRectOverlapping) { + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 2, + .height = 2 + }; + struct mRectangle b = { + .x = 1, + .y = 1, + .width = 2, + .height = 2 + }; + mRectangleUnion(&a, &b); + assert_int_equal(a.x, 0); + assert_int_equal(a.y, 0); + assert_int_equal(a.width, 3); + assert_int_equal(a.height, 3); +} + +M_TEST_DEFINE(unionRectSubRect) { + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 3, + .height = 3 + }; + struct mRectangle b = { + .x = 1, + .y = 1, + .width = 1, + .height = 1 + }; + mRectangleUnion(&a, &b); + assert_int_equal(a.x, 0); + assert_int_equal(a.y, 0); + assert_int_equal(a.width, 3); + assert_int_equal(a.height, 3); +} + +M_TEST_DEFINE(unionRectNegativeOrigin) { + struct mRectangle a = { + .x = -1, + .y = -1, + .width = 1, + .height = 1 + }; + struct mRectangle b = { + .x = 0, + .y = 0, + .width = 1, + .height = 1 + }; + mRectangleUnion(&a, &b); + assert_int_equal(a.x, -1); + assert_int_equal(a.y, -1); + assert_int_equal(a.width, 2); + assert_int_equal(a.height, 2); +} + +M_TEST_DEFINE(intersectRectNWNo) { + /* + * A..... + * ...... + * ..RR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectNWCorner0) { + /* + * ...... + * .A.... + * ..RR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 1, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectNWCorner1) { + /* + * ...... + * .AA... + * .AXR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 1, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectNWFullN) { + /* + * ...... + * .AAA.. + * .AXX.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 1, + .width = 3, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectNWFullW) { + /* + * ...... + * .AA... + * .AXR.. + * .AXR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 1, + .width = 2, + .height = 3 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectNNo) { + /* + * ..AA.. + * ...... + * ..RR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 0, + .width = 2, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectN0) { + /* + * ...... + * ..AA.. + * ..RR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 1, + .width = 2, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectN1) { + /* + * ...... + * ..AA.. + * ..XX.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 1, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectNFull) { + /* + * ...... + * ..AA.. + * ..XX.. + * ..XX.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 1, + .width = 2, + .height = 3 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectNENo) { + /* + * .....A + * ...... + * ..RR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 5, + .y = 0, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectNECorner0) { + /* + * ...... + * ....A. + * ..RR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 4, + .y = 0, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectNECorner1) { + /* + * ...... + * ..,AA. + * ..RXA. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 1, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectNEFullN) { + /* + * ...... + * ..AAA. + * ..XXA. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 1, + .width = 3, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectNEFullE) { + /* + * ...... + * ...AA. + * ..RXA. + * ..RXA. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 1, + .width = 2, + .height = 3 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectWNo) { + /* + * ...... + * ...... + * A.RR.. + * A.RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 0, + .y = 2, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectW0) { + /* + * ...... + * ...... + * .ARR.. + * .ARR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 2, + .width = 1, + .height = 2 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectW1) { + /* + * ...... + * ...... + * .AXR.. + * .AXR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 2, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectWFull) { + /* + * ...... + * ...... + * .AXX.. + * .AXX.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 2, + .width = 3, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectSWNo) { + /* + * ...... + * ...... + * ..RR.. + * ..RR.. + * ...... + * A..... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 0, + .y = 5, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectSWCorner0) { + /* + * ...... + * ...... + * ..RR.. + * ..RR.. + * .A.... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 4, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectSWCorner1) { + /* + * ...... + * ...... + * ..RR.. + * .AXR.. + * .AA... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 3, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectSWFullS) { + /* + * ...... + * ...... + * ..RR.. + * .AXX.. + * .AAA.. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 3, + .width = 3, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectSWFullW) { + /* + * ...... + * ...... + * .AXR.. + * .AXR.. + * .AA... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 1, + .y = 2, + .width = 2, + .height = 3 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectSNo) { + /* + * ...... + * ...... + * ..RR.. + * ..RR.. + * ...... + * ..AA.. + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 5, + .width = 2, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectS0) { + /* + * ...... + * ...... + * ..RR.. + * ..RR.. + * ..AA.. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 4, + .width = 2, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectS1) { + /* + * ...... + * ...... + * ..RR.. + * ..XX.. + * ..AA.. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 3, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectSFull) { + /* + * ...... + * ...... + * ..XX.. + * ..XX.. + * ..AA.. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 2, + .width = 2, + .height = 3 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectSENo) { + /* + * ...... + * ...... + * ..RR.. + * ..RR.. + * ...... + * .....A + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 5, + .y = 5, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectSECorner0) { + /* + * ...... + * ...... + * ..RR.. + * ..RR.. + * ....A. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 4, + .y = 4, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectSECorner1) { + /* + * ...... + * ..,... + * ..RR.. + * ..RXA. + * ...AA. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 3, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectSEFullS) { + /* + * ...... + * ...... + * ..RR.. + * ..XXA. + * ..AAA. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 3, + .width = 3, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectSEFullE) { + /* + * ...... + * ...... + * ..RXA. + * ..RXA. + * ...AA. + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 2, + .width = 2, + .height = 3 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectENo) { + /* + * ...... + * ...... + * ..RR.A + * ..RR.A + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 5, + .y = 2, + .width = 1, + .height = 1 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectE0) { + /* + * ...... + * ...... + * ..RRA. + * ..RRA. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 4, + .y = 2, + .width = 1, + .height = 2 + }; + assert_false(mRectangleIntersection(&ref, &a)); +} + +M_TEST_DEFINE(intersectRectE1) { + /* + * ...... + * ...... + * ..RXA. + * ..RXA. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 2, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectEFull) { + /* + * ...... + * ...... + * ..XXA. + * ..XXA. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 2, + .width = 3, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectInternalNE) { + /* + * ...... + * ...... + * ..XR.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 2, + .width = 1, + .height = 1 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectInternalNW) { + /* + * ...... + * ...... + * ..RX.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 2, + .width = 1, + .height = 1 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectInternalSE) { + /* + * ...... + * ...... + * ..RR.. + * ..XR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 3, + .width = 1, + .height = 1 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectInternalSW) { + /* + * ...... + * ...... + * ..RR.. + * ..RX.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 3, + .width = 1, + .height = 1 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectInternalN) { + /* + * ...... + * ...... + * ..XX.. + * ..RR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 2, + .width = 2, + .height = 1 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectInternalW) { + /* + * ...... + * ...... + * ..XR.. + * ..XR.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 2, + .width = 1, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectInternalS) { + /* + * ...... + * ...... + * ..RR.. + * ..XX.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 3, + .width = 2, + .height = 1 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 3); + assert_int_equal(ref.height, 1); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(intersectRectInternalE) { + /* + * ...... + * ...... + * ..RX.. + * ..RX.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 3, + .y = 2, + .width = 1, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 3); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 1); +} + +M_TEST_DEFINE(intersectRectEqual) { + /* + * ...... + * ...... + * ..XX.. + * ..XX.. + * ...... + * ...... + */ + struct mRectangle ref = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + struct mRectangle a = { + .x = 2, + .y = 2, + .width = 2, + .height = 2 + }; + assert_true(mRectangleIntersection(&ref, &a)); + assert_int_equal(ref.x, 2); + assert_int_equal(ref.y, 2); + assert_int_equal(ref.height, 2); + assert_int_equal(ref.width, 2); +} + +M_TEST_DEFINE(centerRectBasic) { + struct mRectangle ref = { + .x = 0, + .y = 0, + .width = 4, + .height = 4 + }; + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 2, + .height = 2 + }; + mRectangleCenter(&ref, &a); + assert_int_equal(a.x, 1); + assert_int_equal(a.y, 1); +} + +M_TEST_DEFINE(centerRectRoundDown) { + struct mRectangle ref = { + .x = 0, + .y = 0, + .width = 4, + .height = 4 + }; + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 1, + .height = 1 + }; + mRectangleCenter(&ref, &a); + assert_int_equal(a.x, 1); + assert_int_equal(a.y, 1); +} + +M_TEST_DEFINE(centerRectRoundDown2) { + struct mRectangle ref = { + .x = 0, + .y = 0, + .width = 4, + .height = 4 + }; + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 3, + .height = 2 + }; + mRectangleCenter(&ref, &a); + assert_int_equal(a.x, 0); + assert_int_equal(a.y, 1); +} + +M_TEST_DEFINE(centerRectOffset) { + struct mRectangle ref = { + .x = 1, + .y = 1, + .width = 4, + .height = 4 + }; + struct mRectangle a = { + .x = 0, + .y = 0, + .width = 2, + .height = 2 + }; + mRectangleCenter(&ref, &a); + assert_int_equal(a.x, 2); + assert_int_equal(a.y, 2); +} + +M_TEST_SUITE_DEFINE(Geometry, + cmocka_unit_test(unionRectOrigin), + cmocka_unit_test(unionRectOriginSwapped), + cmocka_unit_test(unionRectNonOrigin), + cmocka_unit_test(unionRectOverlapping), + cmocka_unit_test(unionRectSubRect), + cmocka_unit_test(unionRectNegativeOrigin), + cmocka_unit_test(intersectRectNWNo), + cmocka_unit_test(intersectRectNWCorner0), + cmocka_unit_test(intersectRectNWCorner1), + cmocka_unit_test(intersectRectNWFullN), + cmocka_unit_test(intersectRectNWFullW), + cmocka_unit_test(intersectRectNNo), + cmocka_unit_test(intersectRectN0), + cmocka_unit_test(intersectRectN1), + cmocka_unit_test(intersectRectNFull), + cmocka_unit_test(intersectRectNENo), + cmocka_unit_test(intersectRectNECorner0), + cmocka_unit_test(intersectRectNECorner1), + cmocka_unit_test(intersectRectNEFullN), + cmocka_unit_test(intersectRectNEFullE), + cmocka_unit_test(intersectRectWNo), + cmocka_unit_test(intersectRectW0), + cmocka_unit_test(intersectRectW1), + cmocka_unit_test(intersectRectWFull), + cmocka_unit_test(intersectRectSWNo), + cmocka_unit_test(intersectRectSWCorner0), + cmocka_unit_test(intersectRectSWCorner1), + cmocka_unit_test(intersectRectSWFullS), + cmocka_unit_test(intersectRectSWFullW), + cmocka_unit_test(intersectRectSNo), + cmocka_unit_test(intersectRectS0), + cmocka_unit_test(intersectRectS1), + cmocka_unit_test(intersectRectSFull), + cmocka_unit_test(intersectRectSENo), + cmocka_unit_test(intersectRectSECorner0), + cmocka_unit_test(intersectRectSECorner1), + cmocka_unit_test(intersectRectSEFullS), + cmocka_unit_test(intersectRectSEFullE), + cmocka_unit_test(intersectRectENo), + cmocka_unit_test(intersectRectE0), + cmocka_unit_test(intersectRectE1), + cmocka_unit_test(intersectRectEFull), + cmocka_unit_test(intersectRectInternalNE), + cmocka_unit_test(intersectRectInternalNW), + cmocka_unit_test(intersectRectInternalSE), + cmocka_unit_test(intersectRectInternalSW), + cmocka_unit_test(intersectRectInternalN), + cmocka_unit_test(intersectRectInternalW), + cmocka_unit_test(intersectRectInternalS), + cmocka_unit_test(intersectRectInternalE), + cmocka_unit_test(intersectRectEqual), + cmocka_unit_test(centerRectBasic), + cmocka_unit_test(centerRectRoundDown), + cmocka_unit_test(centerRectRoundDown2), + cmocka_unit_test(centerRectOffset), +) diff --git a/src/util/test/image.c b/src/util/test/image.c new file mode 100644 index 000000000..a27e53d5c --- /dev/null +++ b/src/util/test/image.c @@ -0,0 +1,2086 @@ +/* Copyright (c) 2013-2023 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 +#ifdef USE_PNG +#include +#endif +#include + +M_TEST_DEFINE(zeroDim) { + assert_null(mImageCreate(0, 0, mCOLOR_ABGR8)); + assert_null(mImageCreate(1, 0, mCOLOR_ABGR8)); + assert_null(mImageCreate(0, 1, mCOLOR_ABGR8)); + struct mImage* image = mImageCreate(1, 1, mCOLOR_ABGR8); + assert_non_null(image); + mImageDestroy(image); +} + +M_TEST_DEFINE(pitchRead) { + static uint8_t buffer[12] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB + }; + + struct mImage image = { + .data = buffer, + .height = 1 + }; + int i; + + image.depth = 1; + image.width = 12; + image.format = mCOLOR_L8; + + for (i = 0; i < 12; ++i) { + assert_int_equal(mImageGetPixelRaw(&image, i, 0), i); + } + + image.depth = 2; + image.width = 6; + image.format = mCOLOR_RGB5; + + for (i = 0; i < 6; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, i, 0), (i * 2) << 8 | (i * 2 + 1)); +#else + assert_int_equal(mImageGetPixelRaw(&image, i, 0), (i * 2 + 1) << 8 | (i * 2)); +#endif + } + + image.depth = 3; + image.width = 4; + image.format = mCOLOR_RGB8; + + for (i = 0; i < 4; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, i, 0), (i * 3) << 16 | (i * 3 + 1) << 8 | (i * 3 + 2)); +#else + assert_int_equal(mImageGetPixelRaw(&image, i, 0), (i * 3 + 2) << 16 | (i * 3 + 1) << 8 | (i * 3)); +#endif + } + + image.depth = 4; + image.width = 3; + image.format = mCOLOR_ARGB8; + + for (i = 0; i < 3; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, i, 0), (i * 4) << 24 | (i * 4 + 1) << 16 | (i * 4 + 2) << 8 | (i * 4 + 3)); +#else + assert_int_equal(mImageGetPixelRaw(&image, i, 0), (i * 4 + 3) << 24 | (i * 4 + 2) << 16 | (i * 4 + 1) << 8 | (i * 4)); +#endif + } +} + +M_TEST_DEFINE(strideRead) { + static uint8_t buffer[12] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB + }; + + struct mImage image = { + .data = buffer, + .width = 1 + }; + int i; + + image.depth = 1; + image.stride = 1; + image.height = 12; + image.format = mCOLOR_L8; + + for (i = 0; i < 12; ++i) { + assert_int_equal(mImageGetPixelRaw(&image, 0, i), i); + } + + image.depth = 1; + image.stride = 2; + image.height = 6; + image.format = mCOLOR_L8; + + for (i = 0; i < 6; ++i) { + assert_int_equal(mImageGetPixelRaw(&image, 0, i), i * 2); + } + + image.depth = 2; + image.stride = 1; + image.height = 6; + image.format = mCOLOR_RGB5; + + for (i = 0; i < 6; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 2) << 8 | (i * 2 + 1)); +#else + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 2 + 1) << 8 | (i * 2)); +#endif + } + + image.depth = 2; + image.stride = 2; + image.height = 3; + image.format = mCOLOR_RGB5; + + for (i = 0; i < 3; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 4) << 8 | (i * 4 + 1)); +#else + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 4 + 1) << 8 | (i * 4)); +#endif + } + + image.depth = 3; + image.stride = 1; + image.height = 4; + image.format = mCOLOR_RGB8; + + for (i = 0; i < 4; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 3) << 16 | (i * 3 + 1) << 8 | (i * 3 + 2)); +#else + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 3 + 2) << 16 | (i * 3 + 1) << 8 | (i * 3)); +#endif + } + + image.depth = 3; + image.stride = 2; + image.height = 2; + image.format = mCOLOR_RGB8; + + for (i = 0; i < 2; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 6) << 16 | (i * 6 + 1) << 8 | (i * 6 + 2)); +#else + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 6 + 2) << 16 | (i * 6 + 1) << 8 | (i * 6)); +#endif + } + + image.depth = 4; + image.stride = 1; + image.height = 3; + image.format = mCOLOR_ARGB8; + + for (i = 0; i < 3; ++i) { +#ifdef __BIG_ENDIAN__ + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 4) << 24 | (i * 4 + 1) << 16 | (i * 4 + 2) << 8 | (i * 4 + 3)); +#else + assert_int_equal(mImageGetPixelRaw(&image, 0, i), (i * 4 + 3) << 24 | (i * 4 + 2) << 16 | (i * 4 + 1) << 8 | (i * 4)); +#endif + } +} + +M_TEST_DEFINE(oobRead) { + static uint8_t buffer[8] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + struct mImage image = { + .data = buffer, + .width = 1, + .height = 1, + .stride = 1 + }; + + image.depth = 1; + image.format = mCOLOR_L8; + + assert_int_equal(mImageGetPixelRaw(&image, 0, 0), 0xFF); + assert_int_equal(mImageGetPixelRaw(&image, 1, 0), 0); + assert_int_equal(mImageGetPixelRaw(&image, 0, 1), 0); + assert_int_equal(mImageGetPixelRaw(&image, 1, 1), 0); + + image.depth = 2; + image.format = mCOLOR_RGB5; + + assert_int_equal(mImageGetPixelRaw(&image, 0, 0), 0xFFFF); + assert_int_equal(mImageGetPixelRaw(&image, 1, 0), 0); + assert_int_equal(mImageGetPixelRaw(&image, 0, 1), 0); + assert_int_equal(mImageGetPixelRaw(&image, 1, 1), 0); + + image.depth = 3; + image.format = mCOLOR_RGB8; + + assert_int_equal(mImageGetPixelRaw(&image, 0, 0), 0xFFFFFF); + assert_int_equal(mImageGetPixelRaw(&image, 1, 0), 0); + assert_int_equal(mImageGetPixelRaw(&image, 0, 1), 0); + assert_int_equal(mImageGetPixelRaw(&image, 1, 1), 0); + + image.depth = 4; + image.format = mCOLOR_ARGB8; + + assert_int_equal(mImageGetPixelRaw(&image, 0, 0), 0xFFFFFFFF); + assert_int_equal(mImageGetPixelRaw(&image, 1, 0), 0); + assert_int_equal(mImageGetPixelRaw(&image, 0, 1), 0); + assert_int_equal(mImageGetPixelRaw(&image, 1, 1), 0); +} + +M_TEST_DEFINE(pitchWrite) { + static const uint8_t baseline[12] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB + }; + + uint8_t buffer[12]; + + struct mImage image = { + .data = buffer, + .height = 1 + }; + int i; + + image.depth = 1; + image.width = 12; + image.format = mCOLOR_L8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 12; ++i) { + mImageSetPixelRaw(&image, i, 0, i); + } + assert_memory_equal(baseline, buffer, sizeof(baseline)); + + image.depth = 2; + image.width = 6; + image.format = mCOLOR_RGB5; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 6; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, i, 0, (i * 2) << 8 | (i * 2 + 1)); +#else + mImageSetPixelRaw(&image, i, 0, (i * 2 + 1) << 8 | (i * 2)); +#endif + } + assert_memory_equal(baseline, buffer, sizeof(baseline)); + + image.depth = 3; + image.width = 4; + image.format = mCOLOR_RGB8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 4; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, i, 0, (i * 3) << 16 | (i * 3 + 1) << 8 | (i * 3 + 2)); +#else + mImageSetPixelRaw(&image, i, 0, (i * 3 + 2) << 16 | (i * 3 + 1) << 8 | (i * 3)); +#endif + } + assert_memory_equal(baseline, buffer, sizeof(baseline)); + + image.depth = 4; + image.width = 3; + image.format = mCOLOR_ARGB8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 3; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, i, 0, (i * 4) << 24 | (i * 4 + 1) << 16 | (i * 4 + 2) << 8 | (i * 4 + 3)); +#else + mImageSetPixelRaw(&image, i, 0, (i * 4 + 3) << 24 | (i * 4 + 2) << 16 | (i * 4 + 1) << 8 | (i * 4)); +#endif + } + assert_memory_equal(baseline, buffer, sizeof(baseline)); +} + +M_TEST_DEFINE(strideWrite) { + static const uint8_t baseline[12] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB + }; + static const uint8_t baseline2x1[12] = { + 0x0, 0x0, 0x2, 0x0, 0x4, 0x0, 0x6, 0x0, 0x8, 0x0, 0xA, 0x0 + }; + static const uint8_t baseline2x2[12] = { + 0x0, 0x1, 0x0, 0x0, 0x4, 0x5, 0x0, 0x0, 0x8, 0x9, 0x0, 0x0 + }; + static const uint8_t baseline3x2[12] = { + 0x0, 0x1, 0x2, 0x0, 0x0, 0x0, 0x6, 0x7, 0x8, 0x0, 0x0, 0x0 + }; + + uint8_t buffer[12]; + + struct mImage image = { + .data = buffer, + .width = 1 + }; + int i; + + image.depth = 1; + image.stride = 1; + image.height = 12; + image.format = mCOLOR_L8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 12; ++i) { + mImageSetPixelRaw(&image, 0, i, i); + } + assert_memory_equal(baseline, buffer, sizeof(buffer)); + + image.depth = 1; + image.stride = 2; + image.height = 6; + image.format = mCOLOR_L8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 6; ++i) { + mImageSetPixelRaw(&image, 0, i, i * 2); + } + assert_memory_equal(baseline2x1, buffer, sizeof(buffer)); + + image.depth = 2; + image.stride = 1; + image.height = 6; + image.format = mCOLOR_RGB5; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 6; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, 0, i, (i * 2) << 8 | (i * 2 + 1)); +#else + mImageSetPixelRaw(&image, 0, i, (i * 2 + 1) << 8 | (i * 2)); +#endif + } + assert_memory_equal(baseline, buffer, sizeof(buffer)); + + image.depth = 2; + image.stride = 2; + image.height = 3; + image.format = mCOLOR_RGB5; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 3; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, 0, i, (i * 4) << 8 | (i * 4 + 1)); +#else + mImageSetPixelRaw(&image, 0, i, (i * 4 + 1) << 8 | (i * 4)); +#endif + } + assert_memory_equal(baseline2x2, buffer, sizeof(buffer)); + + image.depth = 3; + image.stride = 1; + image.height = 4; + image.format = mCOLOR_RGB8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 4; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, 0, i, (i * 3) << 16 | (i * 3 + 1) << 8 | (i * 3 + 2)); +#else + mImageSetPixelRaw(&image, 0, i, (i * 3 + 2) << 16 | (i * 3 + 1) << 8 | (i * 3)); +#endif + } + assert_memory_equal(baseline, buffer, sizeof(buffer)); + + image.depth = 3; + image.stride = 2; + image.height = 2; + image.format = mCOLOR_RGB8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 2; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, 0, i, (i * 6) << 16 | (i * 6 + 1) << 8 | (i * 6 + 2)); +#else + mImageSetPixelRaw(&image, 0, i, (i * 6 + 2) << 16 | (i * 6 + 1) << 8 | (i * 6)); +#endif + } + assert_memory_equal(baseline3x2, buffer, sizeof(buffer)); + + image.depth = 4; + image.stride = 1; + image.height = 3; + image.format = mCOLOR_ARGB8; + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; i < 3; ++i) { +#ifdef __BIG_ENDIAN__ + mImageSetPixelRaw(&image, 0, i, (i * 4) << 24 | (i * 4 + 1) << 16 | (i * 4 + 2) << 8 | (i * 4 + 3)); +#else + mImageSetPixelRaw(&image, 0, i, (i * 4 + 3) << 24 | (i * 4 + 2) << 16 | (i * 4 + 1) << 8 | (i * 4)); +#endif + } + assert_memory_equal(baseline, buffer, sizeof(buffer)); +} + +M_TEST_DEFINE(oobWrite) { + static uint8_t buffer[8]; + + struct mImage image = { + .data = buffer, + .width = 1, + .height = 1, + .stride = 1 + }; + + image.depth = 1; + image.format = mCOLOR_L8; + + memset(buffer, 0, sizeof(buffer)); + mImageSetPixelRaw(&image, 0, 0, 0xFF); + mImageSetPixelRaw(&image, 1, 0, 0); + mImageSetPixelRaw(&image, 0, 1, 0); + mImageSetPixelRaw(&image, 1, 1, 0); + assert_memory_equal(buffer, (&(uint8_t[8]) { 0xFF }), sizeof(buffer)); + + image.depth = 2; + image.format = mCOLOR_RGB5; + + memset(buffer, 0, sizeof(buffer)); + mImageSetPixelRaw(&image, 0, 0, 0xFFFF); + mImageSetPixelRaw(&image, 1, 0, 0); + mImageSetPixelRaw(&image, 0, 1, 0); + mImageSetPixelRaw(&image, 1, 1, 0); + assert_memory_equal(buffer, (&(uint8_t[8]) { 0xFF, 0xFF }), sizeof(buffer)); + + image.depth = 3; + image.format = mCOLOR_RGB8; + + memset(buffer, 0, sizeof(buffer)); + mImageSetPixelRaw(&image, 0, 0, 0xFFFFFF); + mImageSetPixelRaw(&image, 1, 0, 0); + mImageSetPixelRaw(&image, 0, 1, 0); + mImageSetPixelRaw(&image, 1, 1, 0); + assert_memory_equal(buffer, (&(uint8_t[8]) { 0xFF, 0xFF, 0xFF }), sizeof(buffer)); + + image.depth = 4; + image.format = mCOLOR_ARGB8; + + memset(buffer, 0, sizeof(buffer)); + mImageSetPixelRaw(&image, 0, 0, 0xFFFFFFFF); + mImageSetPixelRaw(&image, 1, 0, 0); + mImageSetPixelRaw(&image, 0, 1, 0); + mImageSetPixelRaw(&image, 1, 1, 0); + assert_memory_equal(buffer, (&(uint8_t[8]) { 0xFF, 0xFF, 0xFF, 0xFF }), sizeof(buffer)); +} + +M_TEST_DEFINE(paletteAccess) { + struct mImage* image = mImageCreate(1, 1, mCOLOR_PAL8); + mImageSetPaletteSize(image, 1); + + mImageSetPaletteEntry(image, 0, 0xFF00FF00); + mImageSetPixelRaw(image, 0, 0, 0); + assert_int_equal(mImageGetPixelRaw(image, 0, 0), 0); + assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF00FF00); + + mImageSetPaletteEntry(image, 0, 0x01234567); + assert_int_equal(mImageGetPixelRaw(image, 0, 0), 0); + assert_int_equal(mImageGetPixel(image, 0, 0), 0x01234567); + + mImageDestroy(image); +} + +#ifdef USE_PNG +M_TEST_DEFINE(loadPng24) { + const uint8_t data[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x08, 0x02, 0x00, 0x00, 0x00, 0xfd, 0xd4, 0x9a, 0x73, 0x00, 0x00, 0x00, + 0x12, 0x49, 0x44, 0x41, 0x54, 0x08, 0x99, 0x63, 0xf8, 0xff, 0xff, 0x3f, + 0x03, 0x03, 0x03, 0x03, 0x84, 0x00, 0x00, 0x2a, 0xe3, 0x04, 0xfc, 0xe8, + 0x51, 0xc0, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 + }; + + struct VFile* vf = VFileFromConstMemory(data, sizeof(data)); + struct mImage* image = mImageLoadVF(vf); + vf->close(vf); + + assert_non_null(image); + assert_int_equal(image->width, 2); + assert_int_equal(image->height, 2); + assert_int_equal(image->format, mCOLOR_XBGR8); + + assert_int_equal(mImageGetPixel(image, 0, 0) & 0xFFFFFF, 0xFFFFFF); + assert_int_equal(mImageGetPixel(image, 1, 0) & 0xFFFFFF, 0x000000); + assert_int_equal(mImageGetPixel(image, 0, 1) & 0xFFFFFF, 0xFF0000); + assert_int_equal(mImageGetPixel(image, 1, 1) & 0xFFFFFF, 0x0000FF); + + mImageDestroy(image); +} + +M_TEST_DEFINE(loadPng32) { + const uint8_t data[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x72, 0xb6, 0x0d, 0x24, 0x00, 0x00, 0x00, + 0x1a, 0x49, 0x44, 0x41, 0x54, 0x08, 0x99, 0x05, 0xc1, 0x31, 0x01, 0x00, + 0x00, 0x08, 0xc0, 0x20, 0x6c, 0x66, 0x25, 0xfb, 0x1f, 0x13, 0xa6, 0x0a, + 0xa7, 0x5a, 0x78, 0x58, 0x7b, 0x07, 0xac, 0xe9, 0x00, 0x3d, 0x95, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + }; + + struct VFile* vf = VFileFromConstMemory(data, sizeof(data)); + struct mImage* image = mImageLoadVF(vf); + vf->close(vf); + + assert_non_null(image); + assert_int_equal(image->width, 2); + assert_int_equal(image->height, 2); + assert_int_equal(image->format, mCOLOR_ABGR8); + + assert_int_equal(mImageGetPixel(image, 0, 0) >> 24, 0xFF); + assert_int_equal(mImageGetPixel(image, 1, 0) >> 24, 0x70); + assert_int_equal(mImageGetPixel(image, 0, 1) >> 24, 0x40); + assert_int_equal(mImageGetPixel(image, 1, 1) >> 24, 0x00); + + mImageDestroy(image); +} + +M_TEST_DEFINE(loadPngPalette) { + const uint8_t data[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x08, 0x03, 0x00, 0x00, 0x00, 0x45, 0x68, 0xfd, 0x16, 0x00, 0x00, 0x00, + 0x0c, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x9b, 0xc0, 0x13, 0xdc, 0x00, 0x00, 0x00, + 0x04, 0x74, 0x52, 0x4e, 0x53, 0x00, 0xc0, 0x80, 0x40, 0x6f, 0x63, 0x29, + 0x01, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, 0x54, 0x08, 0x99, 0x63, + 0x60, 0x60, 0x64, 0x60, 0x62, 0x06, 0x00, 0x00, 0x11, 0x00, 0x07, 0x69, + 0xe2, 0x2a, 0x44, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82 + }; + + struct VFile* vf = VFileFromConstMemory(data, sizeof(data)); + struct mImage* image = mImageLoadVF(vf); + vf->close(vf); + + assert_non_null(image); + assert_int_equal(image->width, 2); + assert_int_equal(image->height, 2); + assert_int_equal(image->format, mCOLOR_PAL8); + + assert_int_equal(mImageGetPixel(image, 0, 0), 0x00000000); + assert_int_equal(mImageGetPixel(image, 1, 0), 0xC0FF0000); + assert_int_equal(mImageGetPixel(image, 0, 1), 0x8000FF00); + assert_int_equal(mImageGetPixel(image, 1, 1), 0x400000FF); + + mImageDestroy(image); +} + +M_TEST_DEFINE(savePngNative) { + struct mImage* image = mImageCreate(1, 1, mCOLOR_ABGR8); + mImageSetPixel(image, 0, 0, 0x01234567); + + struct VFile* vf = VFileMemChunk(NULL, 0); + assert_true(mImageSaveVF(image, vf, "png")); + mImageDestroy(image); + + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + assert_true(isPNG(vf)); + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + + image = mImageLoadVF(vf); + vf->close(vf); + assert_non_null(image); + assert_int_equal(mImageGetPixel(image, 0, 0), 0x01234567); + mImageDestroy(image); +} + +M_TEST_DEFINE(savePngNonNative) { + struct mImage* image = mImageCreate(1, 1, mCOLOR_ARGB8); + mImageSetPixel(image, 0, 0, 0x01234567); + + struct VFile* vf = VFileMemChunk(NULL, 0); + assert_true(mImageSaveVF(image, vf, "png")); + mImageDestroy(image); + + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + assert_true(isPNG(vf)); + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + + image = mImageLoadVF(vf); + vf->close(vf); + assert_non_null(image); + assert_int_equal(image->format, mCOLOR_ABGR8); + assert_int_equal(mImageGetPixel(image, 0, 0), 0x01234567); + mImageDestroy(image); +} + +M_TEST_DEFINE(savePngRoundTrip) { + const enum mColorFormat formats[] = { + mCOLOR_XBGR8, mCOLOR_XRGB8, + mCOLOR_BGRX8, mCOLOR_RGBX8, + mCOLOR_ABGR8, mCOLOR_ARGB8, + mCOLOR_BGRA8, mCOLOR_RGBA8, + mCOLOR_RGB5, mCOLOR_BGR5, + mCOLOR_ARGB5, mCOLOR_ABGR5, + mCOLOR_RGBA5, mCOLOR_BGRA5, + mCOLOR_RGB565, mCOLOR_BGR565, + mCOLOR_RGB8, mCOLOR_BGR8, + 0 + }; + + int i; + for (i = 0; formats[i]; ++i) { + struct mImage* image = mImageCreate(2, 2, formats[i]); + mImageSetPixel(image, 0, 0, 0xFF181008); + mImageSetPixel(image, 1, 0, 0xFF100818); + mImageSetPixel(image, 0, 1, 0xFF081810); + mImageSetPixel(image, 1, 1, 0xFF181008); + assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF181008); + assert_int_equal(mImageGetPixel(image, 1, 0), 0xFF100818); + assert_int_equal(mImageGetPixel(image, 0, 1), 0xFF081810); + assert_int_equal(mImageGetPixel(image, 1, 1), 0xFF181008); + + struct VFile* vf = VFileMemChunk(NULL, 0); + assert_true(mImageSaveVF(image, vf, "png")); + mImageDestroy(image); + + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + assert_true(isPNG(vf)); + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + + image = mImageLoadVF(vf); + vf->close(vf); + assert_non_null(image); + assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF181008); + assert_int_equal(mImageGetPixel(image, 1, 0), 0xFF100818); + assert_int_equal(mImageGetPixel(image, 0, 1), 0xFF081810); + assert_int_equal(mImageGetPixel(image, 1, 1), 0xFF181008); + mImageDestroy(image); + } +} + +M_TEST_DEFINE(savePngL8) { + struct mImage* image = mImageCreate(2, 2, mCOLOR_L8); + mImageSetPixel(image, 0, 0, 0xFF000000); + mImageSetPixel(image, 1, 0, 0xFF555555); + mImageSetPixel(image, 0, 1, 0xFFAAAAAA); + mImageSetPixel(image, 1, 1, 0xFFFFFFFF); + assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF000000); + assert_int_equal(mImageGetPixel(image, 1, 0), 0xFF555555); + assert_int_equal(mImageGetPixel(image, 0, 1), 0xFFAAAAAA); + assert_int_equal(mImageGetPixel(image, 1, 1), 0xFFFFFFFF); + + struct VFile* vf = VFileMemChunk(NULL, 0); + assert_true(mImageSaveVF(image, vf, "png")); + mImageDestroy(image); + + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + assert_true(isPNG(vf)); + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + + image = mImageLoadVF(vf); + vf->close(vf); + assert_non_null(image); + assert_int_equal(mImageGetPixel(image, 0, 0), 0xFF000000); + assert_int_equal(mImageGetPixel(image, 1, 0), 0xFF555555); + assert_int_equal(mImageGetPixel(image, 0, 1), 0xFFAAAAAA); + assert_int_equal(mImageGetPixel(image, 1, 1), 0xFFFFFFFF); + mImageDestroy(image); +} + +M_TEST_DEFINE(savePngPal8) { + struct mImage* image = mImageCreate(2, 2, mCOLOR_PAL8); + mImageSetPaletteSize(image, 4); + mImageSetPaletteEntry(image, 0, 0x00000000); + mImageSetPaletteEntry(image, 1, 0x40FF0000); + mImageSetPaletteEntry(image, 2, 0x8000FF00); + mImageSetPaletteEntry(image, 3, 0xC00000FF); + + mImageSetPixelRaw(image, 0, 0, 0); + mImageSetPixelRaw(image, 1, 0, 1); + mImageSetPixelRaw(image, 0, 1, 2); + mImageSetPixelRaw(image, 1, 1, 3); + assert_int_equal(mImageGetPixel(image, 0, 0), 0x00000000); + assert_int_equal(mImageGetPixel(image, 1, 0), 0x40FF0000); + assert_int_equal(mImageGetPixel(image, 0, 1), 0x8000FF00); + assert_int_equal(mImageGetPixel(image, 1, 1), 0xC00000FF); + + struct VFile* vf = VFileMemChunk(NULL, 0); + assert_true(mImageSaveVF(image, vf, "png")); + mImageDestroy(image); + + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + assert_true(isPNG(vf)); + assert_int_equal(vf->seek(vf, 0, SEEK_SET), 0); + + image = mImageLoadVF(vf); + vf->close(vf); + assert_non_null(image); + assert_int_equal(image->format, mCOLOR_PAL8); + assert_int_equal(mImageGetPixelRaw(image, 0, 0), 0); + assert_int_equal(mImageGetPixelRaw(image, 1, 0), 1); + assert_int_equal(mImageGetPixelRaw(image, 0, 1), 2); + assert_int_equal(mImageGetPixelRaw(image, 1, 1), 3); + assert_int_equal(mImageGetPixel(image, 0, 0), 0x00000000); + assert_int_equal(mImageGetPixel(image, 1, 0), 0x40FF0000); + assert_int_equal(mImageGetPixel(image, 0, 1), 0x8000FF00); + assert_int_equal(mImageGetPixel(image, 1, 1), 0xC00000FF); + mImageDestroy(image); +} +#endif + +M_TEST_DEFINE(convert1x1) { + const enum mColorFormat formats[] = { + mCOLOR_XBGR8, mCOLOR_XRGB8, + mCOLOR_BGRX8, mCOLOR_RGBX8, + mCOLOR_ABGR8, mCOLOR_ARGB8, + mCOLOR_BGRA8, mCOLOR_RGBA8, + mCOLOR_RGB5, mCOLOR_BGR5, + mCOLOR_RGB565, mCOLOR_BGR565, + mCOLOR_ARGB5, mCOLOR_ABGR5, + mCOLOR_RGBA5, mCOLOR_BGRA5, + mCOLOR_RGB8, mCOLOR_BGR8, + mCOLOR_L8, + 0 + }; + + int i, j; + for (i = 0; formats[i]; ++i) { + for (j = 0; formats[j]; ++j) { + struct mImage* src = mImageCreate(1, 1, formats[i]); + mImageSetPixel(src, 0, 0, 0xFF181818); + + struct mImage* dst = mImageConvertToFormat(src, formats[j]); + assert_non_null(dst); + assert_int_equal(dst->format, formats[j]); + assert_int_equal(mImageGetPixel(dst, 0, 0), 0xFF181818); + + mImageDestroy(src); + mImageDestroy(dst); + } + } +} + +M_TEST_DEFINE(convert2x1) { + const enum mColorFormat formats[] = { + mCOLOR_XBGR8, mCOLOR_XRGB8, + mCOLOR_BGRX8, mCOLOR_RGBX8, + mCOLOR_ABGR8, mCOLOR_ARGB8, + mCOLOR_BGRA8, mCOLOR_RGBA8, + mCOLOR_RGB5, mCOLOR_BGR5, + mCOLOR_RGB565, mCOLOR_BGR565, + mCOLOR_ARGB5, mCOLOR_ABGR5, + mCOLOR_RGBA5, mCOLOR_BGRA5, + mCOLOR_RGB8, mCOLOR_BGR8, + mCOLOR_L8, + 0 + }; + + int i, j; + for (i = 0; formats[i]; ++i) { + for (j = 0; formats[j]; ++j) { + struct mImage* src = mImageCreate(2, 1, formats[i]); + mImageSetPixel(src, 0, 0, 0xFF181818); + mImageSetPixel(src, 1, 0, 0xFF101010); + + struct mImage* dst = mImageConvertToFormat(src, formats[j]); + assert_non_null(dst); + assert_int_equal(dst->format, formats[j]); + assert_int_equal(mImageGetPixel(dst, 0, 0), 0xFF181818); + assert_int_equal(mImageGetPixel(dst, 1, 0), 0xFF101010); + + mImageDestroy(src); + mImageDestroy(dst); + } + } +} + +M_TEST_DEFINE(convert1x2) { + const enum mColorFormat formats[] = { + mCOLOR_XBGR8, mCOLOR_XRGB8, + mCOLOR_BGRX8, mCOLOR_RGBX8, + mCOLOR_ABGR8, mCOLOR_ARGB8, + mCOLOR_BGRA8, mCOLOR_RGBA8, + mCOLOR_RGB5, mCOLOR_BGR5, + mCOLOR_RGB565, mCOLOR_BGR565, + mCOLOR_ARGB5, mCOLOR_ABGR5, + mCOLOR_RGBA5, mCOLOR_BGRA5, + mCOLOR_RGB8, mCOLOR_BGR8, + mCOLOR_L8, + 0 + }; + + int i, j; + for (i = 0; formats[i]; ++i) { + for (j = 0; formats[j]; ++j) { + struct mImage* src = calloc(1, sizeof(*src)); + src->width = 1; + src->height = 2; + src->stride = 8; // Use an unusual stride to make sure the right parts get copied + src->format = formats[i]; + src->depth = mColorFormatBytes(src->format); + src->data = calloc(src->stride * src->depth, src->height); + mImageSetPixel(src, 0, 0, 0xFF181818); + mImageSetPixel(src, 0, 1, 0xFF101010); + + struct mImage* dst = mImageConvertToFormat(src, formats[j]); + assert_non_null(dst); + assert_int_equal(dst->format, formats[j]); + assert_int_equal(mImageGetPixel(dst, 0, 0), 0xFF181818); + assert_int_equal(mImageGetPixel(dst, 0, 1), 0xFF101010); + + mImageDestroy(src); + mImageDestroy(dst); + } + } +} + +M_TEST_DEFINE(convert2x2) { + const enum mColorFormat formats[] = { + mCOLOR_XBGR8, mCOLOR_XRGB8, + mCOLOR_BGRX8, mCOLOR_RGBX8, + mCOLOR_ABGR8, mCOLOR_ARGB8, + mCOLOR_BGRA8, mCOLOR_RGBA8, + mCOLOR_RGB5, mCOLOR_BGR5, + mCOLOR_RGB565, mCOLOR_BGR565, + mCOLOR_ARGB5, mCOLOR_ABGR5, + mCOLOR_RGBA5, mCOLOR_BGRA5, + mCOLOR_RGB8, mCOLOR_BGR8, + mCOLOR_L8, + 0 + }; + + int i, j; + for (i = 0; formats[i]; ++i) { + for (j = 0; formats[j]; ++j) { + struct mImage* src = calloc(1, sizeof(*src)); + src->width = 2; + src->height = 2; + src->stride = 8; // Use an unusual stride to make sure the right parts get copied + src->format = formats[i]; + src->depth = mColorFormatBytes(src->format); + src->data = calloc(src->stride * src->depth, src->height); + mImageSetPixel(src, 0, 0, 0xFF181818); + mImageSetPixel(src, 0, 1, 0xFF101010); + mImageSetPixel(src, 1, 0, 0xFF000000); + mImageSetPixel(src, 1, 1, 0xFF080808); + + struct mImage* dst = mImageConvertToFormat(src, formats[j]); + assert_non_null(dst); + assert_int_equal(dst->format, formats[j]); + assert_int_equal(mImageGetPixel(dst, 0, 0), 0xFF181818); + assert_int_equal(mImageGetPixel(dst, 0, 1), 0xFF101010); + assert_int_equal(mImageGetPixel(dst, 1, 0), 0xFF000000); + assert_int_equal(mImageGetPixel(dst, 1, 1), 0xFF080808); + + mImageDestroy(src); + mImageDestroy(dst); + } + } +} + +M_TEST_DEFINE(blitBoundaries) { + static const uint32_t spriteBuffer[4] = { + 0xFF000F00, 0xFF000F01, + 0xFF000F10, 0xFF000F11 + }; + static const uint32_t canvasBuffer[9] = { + 0xFF000000, 0xFF000000, 0xFF000000, + 0xFF000000, 0xFF000000, 0xFF000000, + 0xFF000000, 0xFF000000, 0xFF000000 + }; + + struct mImage* sprite = mImageCreateFromConstBuffer(2, 2, 2, mCOLOR_XRGB8, spriteBuffer); + struct mImage* canvas; + +#define COMPARE(AA, BA, CA, AB, BB, CB, AC, BC, CC) \ + assert_int_equal(mImageGetPixel(canvas, 0, 0), 0xFF000000 | (AA)); \ + assert_int_equal(mImageGetPixel(canvas, 1, 0), 0xFF000000 | (BA)); \ + assert_int_equal(mImageGetPixel(canvas, 2, 0), 0xFF000000 | (CA)); \ + assert_int_equal(mImageGetPixel(canvas, 0, 1), 0xFF000000 | (AB)); \ + assert_int_equal(mImageGetPixel(canvas, 1, 1), 0xFF000000 | (BB)); \ + assert_int_equal(mImageGetPixel(canvas, 2, 1), 0xFF000000 | (CB)); \ + assert_int_equal(mImageGetPixel(canvas, 0, 2), 0xFF000000 | (AC)); \ + assert_int_equal(mImageGetPixel(canvas, 1, 2), 0xFF000000 | (BC)); \ + assert_int_equal(mImageGetPixel(canvas, 2, 2), 0xFF000000 | (CC)) + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -2, -2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -1, -2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 0, -2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 1, -2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 2, -2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 3, -2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -2, -1); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -1, -1); + COMPARE(0xF11, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 0, -1); + COMPARE(0xF10, 0xF11, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 1, -1); + COMPARE(0x000, 0xF10, 0xF11, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 2, -1); + COMPARE(0x000, 0x000, 0xF10, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 3, -1); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -2, 0); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -1, 0); + COMPARE(0xF01, 0x000, 0x000, + 0xF11, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 0, 0); + COMPARE(0xF00, 0xF01, 0x000, + 0xF10, 0xF11, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 1, 0); + COMPARE(0x000, 0xF00, 0xF01, + 0x000, 0xF10, 0xF11, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 2, 0); + COMPARE(0x000, 0x000, 0xF00, + 0x000, 0x000, 0xF10, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 3, 0); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -2, 1); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -1, 1); + COMPARE(0x000, 0x000, 0x000, + 0xF01, 0x000, 0x000, + 0xF11, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 0, 1); + COMPARE(0x000, 0x000, 0x000, + 0xF00, 0xF01, 0x000, + 0xF10, 0xF11, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 1, 1); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0xF00, 0xF01, + 0x000, 0xF10, 0xF11); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 2, 1); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0xF00, + 0x000, 0x000, 0xF10); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 3, 1); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -2, 2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -1, 2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0xF01, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 0, 2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0xF00, 0xF01, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 1, 2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0xF00, 0xF01); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 2, 2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0xF00); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 3, 2); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -2, 3); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, -1, 3); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 0, 3); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 1, 3); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 2, 3); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + + canvas = mImageCreateFromConstBuffer(3, 3, 3, mCOLOR_XRGB8, canvasBuffer); + mImageBlit(canvas, sprite, 3, 3); + COMPARE(0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000); + mImageDestroy(canvas); + +#undef COMPARE + mImageDestroy(sprite); +} + +#define COMPARE4(AA, BA, CA, DA, AB, BB, CB, DB, AC, BC, CC, DC, AD, BD, CD, DD) \ + assert_int_equal(mImageGetPixel(image, 0, 0), (AA)); \ + assert_int_equal(mImageGetPixel(image, 1, 0), (BA)); \ + assert_int_equal(mImageGetPixel(image, 2, 0), (CA)); \ + assert_int_equal(mImageGetPixel(image, 3, 0), (DA)); \ + assert_int_equal(mImageGetPixel(image, 0, 1), (AB)); \ + assert_int_equal(mImageGetPixel(image, 1, 1), (BB)); \ + assert_int_equal(mImageGetPixel(image, 2, 1), (CB)); \ + assert_int_equal(mImageGetPixel(image, 3, 1), (DB)); \ + assert_int_equal(mImageGetPixel(image, 0, 2), (AC)); \ + assert_int_equal(mImageGetPixel(image, 1, 2), (BC)); \ + assert_int_equal(mImageGetPixel(image, 2, 2), (CC)); \ + assert_int_equal(mImageGetPixel(image, 3, 2), (DC)); \ + assert_int_equal(mImageGetPixel(image, 0, 3), (AD)); \ + assert_int_equal(mImageGetPixel(image, 1, 3), (BD)); \ + assert_int_equal(mImageGetPixel(image, 2, 3), (CD)); \ + assert_int_equal(mImageGetPixel(image, 3, 3), (DD)) + +#define COMPARE4X(AA, BA, CA, DA, AB, BB, CB, DB, AC, BC, CC, DC, AD, BD, CD, DD) \ + COMPARE4(0xFF000000 | (AA), 0xFF000000 | (BA), 0xFF000000 | (CA), 0xFF000000 | (DA), \ + 0xFF000000 | (AB), 0xFF000000 | (BB), 0xFF000000 | (CB), 0xFF000000 | (DB), \ + 0xFF000000 | (AC), 0xFF000000 | (BC), 0xFF000000 | (CC), 0xFF000000 | (DC), \ + 0xFF000000 | (AD), 0xFF000000 | (BD), 0xFF000000 | (CD), 0xFF000000 | (DD)) + +#define COMPARE3(AA, BA, CA, AB, BB, CB, AC, BC, CC) \ + assert_int_equal(mImageGetPixel(image, 0, 0), (AA)); \ + assert_int_equal(mImageGetPixel(image, 1, 0), (BA)); \ + assert_int_equal(mImageGetPixel(image, 2, 0), (CA)); \ + assert_int_equal(mImageGetPixel(image, 0, 1), (AB)); \ + assert_int_equal(mImageGetPixel(image, 1, 1), (BB)); \ + assert_int_equal(mImageGetPixel(image, 2, 1), (CB)); \ + assert_int_equal(mImageGetPixel(image, 0, 2), (AC)); \ + assert_int_equal(mImageGetPixel(image, 1, 2), (BC)); \ + assert_int_equal(mImageGetPixel(image, 2, 2), (CC)) + +#define COMPARE3X(AA, BA, CA, AB, BB, CB, AC, BC, CC) \ + COMPARE3(0xFF000000 | (AA), 0xFF000000 | (BA), 0xFF000000 | (CA), \ + 0xFF000000 | (AB), 0xFF000000 | (BB), 0xFF000000 | (CB), \ + 0xFF000000 | (AC), 0xFF000000 | (BC), 0xFF000000 | (CC)) + +M_TEST_DEFINE(painterFillRectangle) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 1, 1, 2, 2); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x0000FF, 0x0000FF, 0x000000, + 0x000000, 0x0000FF, 0x0000FF, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, -1, -1, 2, 2); + COMPARE4X(0x0000FF, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 3, -1, 2, 2); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x0000FF, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, -1, 3, 2, 2); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x0000FF, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 3, 3, 2, 2); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x0000FF); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + painter.fillColor = 0xFF00FF00; + mPainterDrawRectangle(&painter, 1, 1, 3, 3); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x000000, + 0x0000FF, 0x00FF00, 0x00FF00, 0x00FF00, + 0x0000FF, 0x00FF00, 0x00FF00, 0x00FF00, + 0x000000, 0x00FF00, 0x00FF00, 0x00FF00); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterFillRectangleBlend) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(3, 3, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0x400000FF; + mPainterDrawRectangle(&painter, 0, 0, 2, 2); + painter.fillColor = 0x40FF0000; + mPainterDrawRectangle(&painter, 1, 1, 2, 2); + COMPARE3(0x400000FF, 0x400000FF, 0x00000000, + 0x400000FF, 0x40FF0000, 0x40FF0000, + 0x00000000, 0x40FF0000, 0x40FF0000); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = true; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0x400000FF; + mPainterDrawRectangle(&painter, 0, 0, 2, 2); + painter.fillColor = 0x40FF0000; + mPainterDrawRectangle(&painter, 1, 1, 2, 2); + COMPARE3(0x400000FF, 0x400000FF, 0x00000000, + 0x400000FF, 0x6F91006D, 0x40FF0000, + 0x00000000, 0x40FF0000, 0x40FF0000); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterFillRectangleInvalid) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 1, 1, -1, -1); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterStrokeRectangle) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 1, 1, 2, 2); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x0000FF, 0x0000FF, 0x000000, + 0x000000, 0x0000FF, 0x0000FF, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, -1, -1, 3, 3); + COMPARE4X(0x000000, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 2, -1, 3, 3); + COMPARE4X(0x000000, 0x000000, 0x0000FF, 0x000000, + 0x000000, 0x000000, 0x0000FF, 0x0000FF, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, -1, 2, 3, 3); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x000000, 0x0000FF, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 2, 2, 3, 3); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x0000FF, 0x0000FF, + 0x000000, 0x000000, 0x0000FF, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + painter.strokeColor = 0xFF00FF00; + mPainterDrawRectangle(&painter, 1, 1, 3, 3); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x000000, + 0x0000FF, 0x00FF00, 0x00FF00, 0x00FF00, + 0x0000FF, 0x00FF00, 0x0000FF, 0x00FF00, + 0x000000, 0x00FF00, 0x00FF00, 0x00FF00); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterStrokeRectangleWidth) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 4, 4); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x000000, 0x000000, 0x0000FF, + 0x0000FF, 0x000000, 0x000000, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 4, 1); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 1, 4); + COMPARE4X(0x0000FF, 0x000000, 0x000000, 0x000000, + 0x0000FF, 0x000000, 0x000000, 0x000000, + 0x0000FF, 0x000000, 0x000000, 0x000000, + 0x0000FF, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 4, 2); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 2, 4); + COMPARE4X(0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 4, 4); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 4, 2); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 2, 4); + COMPARE4X(0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 3; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 4, 2); + COMPARE4X(0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 3; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 0, 0, 2, 4); + COMPARE4X(0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000, + 0x0000FF, 0x0000FF, 0x000000, 0x000000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 4; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 1, 1, 2, 2); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x0000FF, 0x0000FF, 0x000000, + 0x000000, 0x0000FF, 0x0000FF, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterStrokeRectangleBlend) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0x400000FF; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + painter.strokeColor = 0x40FF0000; + mPainterDrawRectangle(&painter, 1, 1, 3, 3); + COMPARE4(0x400000FF, 0x400000FF, 0x400000FF, 0x00000000, + 0x400000FF, 0x40FF0000, 0x40FF0000, 0x40FF0000, + 0x400000FF, 0x40FF0000, 0x400000FF, 0x40FF0000, + 0x00000000, 0x40FF0000, 0x40FF0000, 0x40FF0000); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = true; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0x400000FF; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + painter.strokeColor = 0x40FF0000; + mPainterDrawRectangle(&painter, 1, 1, 3, 3); + COMPARE4(0x400000FF, 0x400000FF, 0x400000FF, 0x00000000, + 0x400000FF, 0x40FF0000, 0x6F91006D, 0x40FF0000, + 0x400000FF, 0x6F91006D, 0x400000FF, 0x40FF0000, + 0x00000000, 0x40FF0000, 0x40FF0000, 0x40FF0000); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterStrokeRectangleInvalid) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawRectangle(&painter, 1, 1, -1, -1); + COMPARE4X(0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterDrawRectangle) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(3, 3, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.fillColor = 0x800000FF; + painter.strokeWidth = 1; + painter.strokeColor = 0x4000FF00; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + COMPARE3(0x4000FF00, 0x4000FF00, 0x4000FF00, + 0x4000FF00, 0x800000FF, 0x4000FF00, + 0x4000FF00, 0x4000FF00, 0x4000FF00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = true; + painter.fill = true; + painter.fillColor = 0x800000FF; + painter.strokeWidth = 1; + painter.strokeColor = 0x4000FF00; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + COMPARE3(0x4000FF00, 0x4000FF00, 0x4000FF00, + 0x4000FF00, 0x800000FF, 0x4000FF00, + 0x4000FF00, 0x4000FF00, 0x4000FF00); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.fillColor = 0x800000FF; + painter.strokeWidth = 1; + painter.strokeColor = 0x4000FF00; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + mPainterDrawRectangle(&painter, 1, 1, 3, 3); + COMPARE4(0x4000FF00, 0x4000FF00, 0x4000FF00, 0x00000000, + 0x4000FF00, 0x4000FF00, 0x4000FF00, 0x4000FF00, + 0x4000FF00, 0x4000FF00, 0x800000FF, 0x4000FF00, + 0x00000000, 0x4000FF00, 0x4000FF00, 0x4000FF00); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = true; + painter.fill = true; + painter.fillColor = 0x800000FF; + painter.strokeWidth = 1; + painter.strokeColor = 0x4000FF00; + mPainterDrawRectangle(&painter, 0, 0, 3, 3); + mPainterDrawRectangle(&painter, 1, 1, 3, 3); + COMPARE4(0x4000FF00, 0x4000FF00, 0x4000FF00, 0x00000000, + 0x4000FF00, 0x9F006698, 0x6F00FF00, 0x4000FF00, + 0x4000FF00, 0x6F00FF00, 0x9F0032CC, 0x4000FF00, + 0x00000000, 0x4000FF00, 0x4000FF00, 0x4000FF00); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterDrawLineOctants) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 0, 2, 2); + COMPARE3X(0xFF, 0x00, 0x00, + 0x00, 0xFF, 0x00, + 0x00, 0x00, 0xFF); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 2, 2, 0, 0); + COMPARE3X(0xFF, 0x00, 0x00, + 0x00, 0xFF, 0x00, + 0x00, 0x00, 0xFF); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 2, 0, 0, 2); + COMPARE3X(0x00, 0x00, 0xFF, + 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 2, 2, 0); + COMPARE3X(0x00, 0x00, 0xFF, + 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 0, 2, 1); + COMPARE3X(0xFF, 0xFF, 0x00, + 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 2, 1, 0, 0); + COMPARE3X(0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, + 0x00, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 0, 1, 2); + COMPARE3X(0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 1, 2, 0, 0); + COMPARE3X(0xFF, 0x00, 0x00, + 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterDrawLineWidth) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 0, 3, 3); + COMPARE4X(0xFF, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0xFF, 0xFF); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 3; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 0, 3, 3); + COMPARE4X(0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0xFF, 0xFF); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 3, 0, 0, 3); + COMPARE4X(0x00, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 3; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 3, 0, 0, 3); + COMPARE4X(0x00, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 1, 0, 1, 2); + COMPARE3X(0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 3; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 1, 0, 1, 2); + COMPARE3X(0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 2; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 1, 2, 1); + COMPARE3X(0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 3; + painter.strokeColor = 0xFF0000FF; + mPainterDrawLine(&painter, 0, 1, 2, 1); + COMPARE3X(0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterDrawLineBlend) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(3, 3, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.strokeWidth = 1; + painter.strokeColor = 0x400000FF; + mPainterDrawLine(&painter, 0, 0, 2, 2); + painter.strokeColor = 0x4000FF00; + mPainterDrawLine(&painter, 0, 2, 2, 0); + COMPARE3(0x400000FF, 0x00000000, 0x4000FF00, + 0x00000000, 0x4000FF00, 0x00000000, + 0x4000FF00, 0x00000000, 0x400000FF); + mImageDestroy(image); + + image = mImageCreate(3, 3, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = true; + painter.strokeWidth = 1; + painter.strokeColor = 0x400000FF; + mPainterDrawLine(&painter, 0, 0, 2, 2); + painter.strokeColor = 0x4000FF00; + mPainterDrawLine(&painter, 0, 2, 2, 0); + COMPARE3(0x400000FF, 0x00000000, 0x4000FF00, + 0x00000000, 0x6F00916D, 0x00000000, + 0x4000FF00, 0x00000000, 0x400000FF); + mImageDestroy(image); +} + +M_TEST_DEFINE(painterDrawCircleArea) { + struct mImage* image; + struct mPainter painter; + + int i; + for (i = 4; i < 50; ++i) { + image = mImageCreate(i, i, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawCircle(&painter, 0, 0, i); + + int filled = 0; + + int x, y; + for (y = 0; y < i; ++y) { + for (x = 0; x < i; ++x) { + uint32_t color = mImageGetPixel(image, x, y); + if (color == painter.fillColor) { + ++filled; + } + } + } + float area = i * i; + assert_float_equal(filled / area, M_PI / 4, 0.12); + mImageDestroy(image); + } +} + +M_TEST_DEFINE(painterDrawCircleCircumference) { + struct mImage* image; + struct mPainter painter; + + int i; + for (i = 25; i < 100; ++i) { + image = mImageCreate(i, i, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawCircle(&painter, 0, 0, i); + + int filled = 0; + + int x, y; + for (y = 0; y < i; ++y) { + for (x = 0; x < i; ++x) { + uint32_t color = mImageGetPixel(image, x, y); + if (color == painter.strokeColor) { + ++filled; + } + } + } + assert_float_equal(filled / (float) i, M_PI, M_PI * 0.11); + mImageDestroy(image); + } +} + +M_TEST_DEFINE(painterDrawCircleOffset) { + struct mImage* image; + struct mPainter painter; + + int i; + for (i = 4; i < 20; ++i) { + image = mImageCreate(i * 2, i * 2, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawCircle(&painter, 0, 0, i); + mPainterDrawCircle(&painter, i, 0, i); + mPainterDrawCircle(&painter, 0, i, i); + mPainterDrawCircle(&painter, i, i, i); + + int x, y; + for (y = 0; y < i; ++y) { + for (x = 0; x < i; ++x) { + uint32_t color = mImageGetPixel(image, x, y); + assert_int_equal(color, mImageGetPixel(image, x + i, y)); + assert_int_equal(color, mImageGetPixel(image, x, y + i)); + assert_int_equal(color, mImageGetPixel(image, x + i, y + i)); + } + } + mImageDestroy(image); + } +} + +M_TEST_DEFINE(painterDrawCircleBlend) { + struct mImage* image; + struct mPainter painter; + + int i, j; + for (i = 1; i < 10; ++i) { + for (j = 0; j < i / 2 + 1; ++j) { + image = mImageCreate(i, i, mCOLOR_ARGB8); + mPainterInit(&painter, image); + painter.blend = true; + painter.fill = true; + painter.strokeWidth = j; + painter.fillColor = 0x8000FF00; + painter.strokeColor = 0x800000FF; + mPainterDrawCircle(&painter, 0, 0, i); + + int x, y; + for (y = 0; y < i; ++y) { + for (x = 0; x < i; ++x) { + uint32_t color = mImageGetPixel(image, x, y); + if (color != painter.strokeColor && color != painter.fillColor) { + assert_int_equal(color, 0); + } + } + } + mImageDestroy(image); + } + } +} + +M_TEST_DEFINE(painterDrawCircleInvalid) { + struct mImage* image; + struct mPainter painter; + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = true; + painter.strokeWidth = 0; + painter.fillColor = 0xFF0000FF; + mPainterDrawCircle(&painter, 2, 2, -1); + COMPARE4X(0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00); + mImageDestroy(image); + + image = mImageCreate(4, 4, mCOLOR_XRGB8); + mPainterInit(&painter, image); + painter.blend = false; + painter.fill = false; + painter.strokeWidth = 1; + painter.strokeColor = 0xFF0000FF; + mPainterDrawCircle(&painter, 2, 2, -1); + COMPARE4X(0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00); + mImageDestroy(image); +} + +#undef COMPARE3X +#undef COMPARE3 +#undef COMPARE4X +#undef COMPARE4 + +M_TEST_SUITE_DEFINE(Image, + cmocka_unit_test(zeroDim), + cmocka_unit_test(pitchRead), + cmocka_unit_test(strideRead), + cmocka_unit_test(oobRead), + cmocka_unit_test(pitchWrite), + cmocka_unit_test(strideWrite), + cmocka_unit_test(oobWrite), + cmocka_unit_test(paletteAccess), +#ifdef USE_PNG + cmocka_unit_test(loadPng24), + cmocka_unit_test(loadPng32), + cmocka_unit_test(loadPngPalette), + cmocka_unit_test(savePngNative), + cmocka_unit_test(savePngNonNative), + cmocka_unit_test(savePngRoundTrip), + cmocka_unit_test(savePngL8), + cmocka_unit_test(savePngPal8), +#endif + cmocka_unit_test(convert1x1), + cmocka_unit_test(convert2x1), + cmocka_unit_test(convert1x2), + cmocka_unit_test(convert2x2), + cmocka_unit_test(blitBoundaries), + cmocka_unit_test(painterFillRectangle), + cmocka_unit_test(painterFillRectangleBlend), + cmocka_unit_test(painterFillRectangleInvalid), + cmocka_unit_test(painterStrokeRectangle), + cmocka_unit_test(painterStrokeRectangleWidth), + cmocka_unit_test(painterStrokeRectangleBlend), + cmocka_unit_test(painterStrokeRectangleInvalid), + cmocka_unit_test(painterDrawRectangle), + cmocka_unit_test(painterDrawLineOctants), + cmocka_unit_test(painterDrawLineWidth), + cmocka_unit_test(painterDrawLineBlend), + cmocka_unit_test(painterDrawCircleArea), + cmocka_unit_test(painterDrawCircleCircumference), + cmocka_unit_test(painterDrawCircleOffset), + cmocka_unit_test(painterDrawCircleBlend), + cmocka_unit_test(painterDrawCircleInvalid), +) diff --git a/src/util/test/vfs.c b/src/util/test/vfs.c index cc623d1b0..4fd995275 100644 --- a/src/util/test/vfs.c +++ b/src/util/test/vfs.c @@ -84,7 +84,7 @@ M_TEST_DEFINE(resizeMem) { } M_TEST_DEFINE(resizeConstMem) { - uint8_t bytes[32]; + uint8_t bytes[32] = {0}; struct VFile* vf = VFileFromConstMemory(bytes, 32); assert_non_null(vf); assert_int_equal(vf->size(vf), 32); @@ -96,7 +96,7 @@ M_TEST_DEFINE(resizeConstMem) { } M_TEST_DEFINE(resizeMemChunk) { - uint8_t bytes[32]; + uint8_t bytes[32] = {0}; struct VFile* vf = VFileMemChunk(bytes, 32); assert_non_null(vf); assert_int_equal(vf->size(vf), 32); diff --git a/src/util/vector.c b/src/util/vector.c new file mode 100644 index 000000000..28750a1b4 --- /dev/null +++ b/src/util/vector.c @@ -0,0 +1,17 @@ +/* Copyright (c) 2013-2023 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 + +DEFINE_VECTOR(IntList, int); +DEFINE_VECTOR(SInt8List, int8_t); +DEFINE_VECTOR(SInt16List, int16_t); +DEFINE_VECTOR(SInt32List, int32_t); +DEFINE_VECTOR(SIntPtrList, intptr_t); +DEFINE_VECTOR(UInt8List, uint8_t); +DEFINE_VECTOR(UInt16List, uint16_t); +DEFINE_VECTOR(UInt32List, uint32_t); +DEFINE_VECTOR(UIntPtrList, uintptr_t); +DEFINE_VECTOR(StringList, char*); diff --git a/src/util/vfs.c b/src/util/vfs.c index 28d366c53..d99f5020f 100644 --- a/src/util/vfs.c +++ b/src/util/vfs.c @@ -13,6 +13,10 @@ #ifdef __3DS__ #include #endif +#ifdef _WIN32 +#include +#include +#endif struct VFile* VFileOpen(const char* path, int flags) { #ifdef USE_VFS_FILE @@ -207,6 +211,41 @@ void separatePath(const char* path, char* dirname, char* basename, char* extensi } } +bool isAbsolute(const char* path) { + // XXX: Is this robust? +#ifdef _WIN32 + WCHAR wpath[PATH_MAX]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, PATH_MAX); + return !PathIsRelativeW(wpath); +#else + return path[0] == '/'; +#endif +} + +void makeAbsolute(const char* path, const char* base, char* out) { + if (isAbsolute(path)) { + strncpy(out, path, PATH_MAX); + return; + } + + char buf[PATH_MAX]; + snprintf(buf, sizeof(buf), "%s" PATH_SEP "%s", base, path); +#ifdef _WIN32 + WCHAR wbuf[PATH_MAX]; + WCHAR wout[PATH_MAX]; + MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, PATH_MAX); + if (GetFullPathNameW(wbuf, PATH_MAX, wout, NULL)) { + WideCharToMultiByte(CP_UTF8, 0, wout, -1, out, PATH_MAX, 0, 0); + return; + } +#elif defined(HAVE_REALPATH) + if (realpath(buf, out)) { + return; + } +#endif + strncpy(out, buf, PATH_MAX); +} + struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)) { dir->rewind(dir); struct VDirEntry* dirent = dir->listNext(dir); diff --git a/src/util/vfs/vfs-devlist.c b/src/util/vfs/vfs-devlist.c index 667ffd193..8f61d49c8 100644 --- a/src/util/vfs/vfs-devlist.c +++ b/src/util/vfs/vfs-devlist.c @@ -20,7 +20,7 @@ static enum VFSType _vdleType(struct VDirEntry* vde); struct VDirEntryDevList { struct VDirEntry d; size_t index; - char* name; + char name[PATH_MAX + 1]; }; struct VDirDevList { @@ -31,7 +31,7 @@ struct VDirDevList { struct VDir* VDeviceList() { struct VDirDevList* vd = malloc(sizeof(struct VDirDevList)); if (!vd) { - return 0; + return NULL; } vd->d.close = _vdlClose; @@ -44,50 +44,42 @@ struct VDir* VDeviceList() { vd->vde.d.name = _vdleName; vd->vde.d.type = _vdleType; vd->vde.index = 0; - vd->vde.name = 0; + vd->vde.name[0] = '\0'; return &vd->d; } static bool _vdlClose(struct VDir* vd) { struct VDirDevList* vdl = (struct VDirDevList*) vd; - free(vdl->vde.name); free(vdl); return true; } static void _vdlRewind(struct VDir* vd) { struct VDirDevList* vdl = (struct VDirDevList*) vd; - free(vdl->vde.name); - vdl->vde.name = 0; - vdl->vde.index = 3; + vdl->vde.name[0] = '\0'; + vdl->vde.index = 0; } static struct VDirEntry* _vdlListNext(struct VDir* vd) { struct VDirDevList* vdl = (struct VDirDevList*) vd; - if (vdl->vde.name) { - ++vdl->vde.index; - free(vdl->vde.name); - vdl->vde.name = 0; - } while (vdl->vde.index < STD_MAX) { const devoptab_t *devops = devoptab_list[vdl->vde.index]; - if (devops->dirStateSize > 0) { - vdl->vde.name = malloc(strlen(devops->name) + 3); - sprintf(vdl->vde.name, "%s:", devops->name); - return &vdl->vde.d; - } - ++vdl->vde.index; + if (!devops || !devops->name || devops->dirStateSize <= 0) { + continue; + } + snprintf(vdl->vde.name, sizeof(vdl->vde.name), "%s:", devops->name); + return &vdl->vde.d; } - return 0; + return NULL; } static struct VFile* _vdlOpenFile(struct VDir* vd, const char* path, int mode) { UNUSED(vd); UNUSED(path); UNUSED(mode); - return 0; + return NULL; } static struct VDir* _vdlOpenDir(struct VDir* vd, const char* path) { diff --git a/src/util/vfs/vfs-dirent.c b/src/util/vfs/vfs-dirent.c index 610482313..806148b89 100644 --- a/src/util/vfs/vfs-dirent.c +++ b/src/util/vfs/vfs-dirent.c @@ -133,7 +133,7 @@ bool _vdDeleteFile(struct VDir* vd, const char* path) { char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); sprintf(combined, "%s%s%s", dir, PATH_SEP, path); - bool ret = !unlink(combined); + bool ret = !remove(combined); free(combined); return ret; } diff --git a/src/util/vfs/vfs-file.c b/src/util/vfs/vfs-file.c index d3adc3177..4a63e53f8 100644 --- a/src/util/vfs/vfs-file.c +++ b/src/util/vfs/vfs-file.c @@ -151,7 +151,9 @@ static bool _vffSync(struct VFile* vf, void* buffer, size_t size) { fseek(vff->file, 0, SEEK_SET); size_t res = fwrite(buffer, size, 1, vff->file); fseek(vff->file, pos, SEEK_SET); - return res == 1; + if (res != 1) { + return false; + } } return fflush(vff->file) == 0; } diff --git a/src/util/vfs/vfs-lzma.c b/src/util/vfs/vfs-lzma.c index a094c187a..c9f88411d 100644 --- a/src/util/vfs/vfs-lzma.c +++ b/src/util/vfs/vfs-lzma.c @@ -7,7 +7,9 @@ #ifdef USE_LZMA +#include #include +#include #include "third-party/lzma/7z.h" #include "third-party/lzma/7zAlloc.h" @@ -26,15 +28,19 @@ struct VDirEntry7z { char* utf8; }; +struct VDir7zAlloc { + ISzAlloc d; + struct Table allocs; +}; + struct VDir7z { struct VDir d; struct VDirEntry7z dirent; - // What is all this garbage? CFileInStream archiveStream; CLookToRead2 lookStream; CSzArEx db; - ISzAlloc allocImp; + struct VDir7zAlloc allocImp; ISzAlloc allocTempImp; }; @@ -70,6 +76,43 @@ static bool _vd7zDeleteFile(struct VDir* vd, const char* path); static const char* _vde7zName(struct VDirEntry* vde); static enum VFSType _vde7zType(struct VDirEntry* vde); +static void* _vd7zAlloc(ISzAllocPtr p, size_t size) { + struct VDir7zAlloc* alloc = (struct VDir7zAlloc*) p; + void* address; + if (size >= 0x10000) { + address = anonymousMemoryMap(size); + } else { + address = malloc(size); + } + if (address) { + TableInsert(&alloc->allocs, (uintptr_t) address >> 2, (void*) size); + } + return address; +} + +static void _vd7zFree(ISzAllocPtr p, void* address) { + struct VDir7zAlloc* alloc = (struct VDir7zAlloc*) p; + size_t size = (size_t) TableLookup(&alloc->allocs, (uintptr_t) address >> 2); + if (size) { + TableRemove(&alloc->allocs, (uintptr_t) address >> 2); + if (size >= 0x10000) { + mappedMemoryFree(address, size); + } else { + free(address); + } + } +} + +static void* _vd7zAllocTemp(ISzAllocPtr p, size_t size) { + UNUSED(p); + return malloc(size); +} + +static void _vd7zFreeTemp(ISzAllocPtr p, void* address) { + UNUSED(p); + free(address); +} + struct VDir* VDirOpen7z(const char* path, int flags) { if (flags & O_WRONLY || flags & O_CREAT) { return 0; @@ -83,11 +126,12 @@ struct VDir* VDirOpen7z(const char* path, int flags) { return 0; } - vd->allocImp.Alloc = SzAlloc; - vd->allocImp.Free = SzFree; + vd->allocImp.d.Alloc = _vd7zAlloc; + vd->allocImp.d.Free = _vd7zFree; + TableInit(&vd->allocImp.allocs, 0, NULL); - vd->allocTempImp.Alloc = SzAllocTemp; - vd->allocTempImp.Free = SzFreeTemp; + vd->allocTempImp.Alloc = _vd7zAllocTemp; + vd->allocTempImp.Free = _vd7zFreeTemp; FileInStream_CreateVTable(&vd->archiveStream); LookToRead2_CreateVTable(&vd->lookStream, False); @@ -101,11 +145,12 @@ struct VDir* VDirOpen7z(const char* path, int flags) { CrcGenerateTable(); SzArEx_Init(&vd->db); - SRes res = SzArEx_Open(&vd->db, &vd->lookStream.vt, &vd->allocImp, &vd->allocTempImp); + SRes res = SzArEx_Open(&vd->db, &vd->lookStream.vt, &vd->allocImp.d, &vd->allocTempImp); if (res != SZ_OK) { - SzArEx_Free(&vd->db, &vd->allocImp); + SzArEx_Free(&vd->db, &vd->allocImp.d); File_Close(&vd->archiveStream.file); free(vd->lookStream.buf); + TableDeinit(&vd->allocImp.allocs); free(vd); return 0; } @@ -128,7 +173,7 @@ struct VDir* VDirOpen7z(const char* path, int flags) { bool _vf7zClose(struct VFile* vf) { struct VFile7z* vf7z = (struct VFile7z*) vf; - IAlloc_Free(&vf7z->vd->allocImp, vf7z->outBuffer); + IAlloc_Free(&vf7z->vd->allocImp.d, vf7z->outBuffer); free(vf7z); return true; } @@ -215,12 +260,13 @@ ssize_t _vf7zSize(struct VFile* vf) { bool _vd7zClose(struct VDir* vd) { struct VDir7z* vd7z = (struct VDir7z*) vd; - SzArEx_Free(&vd7z->db, &vd7z->allocImp); + SzArEx_Free(&vd7z->db, &vd7z->allocImp.d); File_Close(&vd7z->archiveStream.file); free(vd7z->lookStream.buf); free(vd7z->dirent.utf8); vd7z->dirent.utf8 = 0; + TableDeinit(&vd7z->allocImp.allocs); free(vd7z); return true; @@ -292,7 +338,7 @@ struct VFile* _vd7zOpenFile(struct VDir* vd, const char* path, int mode) { SRes res = SzArEx_Extract(&vd7z->db, &vd7z->lookStream.vt, i, &blockIndex, &vf->outBuffer, &outBufferSize, &vf->bufferOffset, &vf->size, - &vd7z->allocImp, &vd7z->allocTempImp); + &vd7z->allocImp.d, &vd7z->allocTempImp); if (res != SZ_OK) { free(vf); diff --git a/src/util/vfs/vfs-zip.c b/src/util/vfs/vfs-zip.c index 2f8234b94..65e1c1e32 100644 --- a/src/util/vfs/vfs-zip.c +++ b/src/util/vfs/vfs-zip.c @@ -309,6 +309,9 @@ ssize_t _vfzRead(struct VFile* vf, void* buffer, size_t size) { if (!vfz->buffer) { vfz->bufferSize = BLOCK_SIZE; vfz->buffer = malloc(BLOCK_SIZE); + if (vfz->readSize) { + abort(); + } } while (bytesRead < size) { @@ -714,7 +717,7 @@ struct VFile* _vdzOpenFile(struct VDir* vd, const char* path, int mode) { } } - struct VFileZip* vfz = malloc(sizeof(struct VFileZip)); + struct VFileZip* vfz = calloc(1, sizeof(struct VFileZip)); vfz->uz = vdz->uz; vfz->z = vdz->z; vfz->buffer = 0; diff --git a/tools/deploy-mac.py b/tools/deploy-mac.py index 82b8df4f2..89369d163 100755 --- a/tools/deploy-mac.py +++ b/tools/deploy-mac.py @@ -130,6 +130,8 @@ if __name__ == '__main__': parser.add_argument('-I', '--install-name-tool', metavar='INSTALL_NAME_TOOL', default='install_name_tool', help='path to install_name_tool') parser.add_argument('-O', '--otool', metavar='OTOOL', default='otool', help='path to otool') parser.add_argument('-p', '--qt-plugins', metavar='PLUGINS', default='', help='Qt plugins to include (comma-separated)') + parser.add_argument('-s', '--sign', metavar='IDENTITY', help='sign with a given identity') + parser.add_argument('-E', '--entitlements', metavar='ENTITLEMENTS', help='use a given file for entitlements when signing') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='output more information') parser.add_argument('bundle', help='application bundle to deploy') args = parser.parse_args() @@ -168,3 +170,9 @@ if __name__ == '__main__': newPath = os.path.join(newDir, plug) shutil.copy2(os.path.join(qtPath, 'plugins', plugin), newPath) updateMachO(newPath, splitPath(os.path.join(args.bundle, 'Contents/MacOS')), splitPath(args.root)) + if args.sign: + args = ['codesign', '-s', args.sign, '-vf', '-o', 'runtime'] + if args.entitlements: + args.extend(['--entitlements', args.entitlements]) + args.append(args.bundle) + subprocess.check_call(args)